<!DOCTYPE html>
<html lang="en-US">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>学习 axios 源码整体架构，打造属于自己的请求库 | 若川的博客</title>
    <meta name="generator" content="VuePress 1.8.2">
    <link rel="icon" href="/favicon.ico">
    <link rel="mainfest" href="/mainfest.json">
    <meta name="description" content="若川，微信搜索「若川视野」关注我，长期交流学习。写有《学习源码整体架构系列》。包含jquery源码、underscore源码、lodash源码、sentry源码、vuex源码、axios源码、koa源码、redux源码。前端路上，PPT爱好者，所知甚少，唯善学。">
    
    <link rel="preload" href="/assets/css/0.styles.0ad39d54.css" as="style"><link rel="preload" href="/assets/js/app.9fbcafa6.js" as="script"><link rel="preload" href="/assets/js/2.33539d56.js" as="script"><link rel="preload" href="/assets/js/14.c9f20b6b.js" as="script"><link rel="preload" href="/assets/js/23.72249401.js" as="script"><link rel="prefetch" href="/assets/js/10.17a947d6.js"><link rel="prefetch" href="/assets/js/11.599e7eee.js"><link rel="prefetch" href="/assets/js/12.574e6f26.js"><link rel="prefetch" href="/assets/js/13.3a93edbc.js"><link rel="prefetch" href="/assets/js/15.c6b03e37.js"><link rel="prefetch" href="/assets/js/16.c445ccb9.js"><link rel="prefetch" href="/assets/js/17.60b94fab.js"><link rel="prefetch" href="/assets/js/18.86de3f95.js"><link rel="prefetch" href="/assets/js/19.6fedd448.js"><link rel="prefetch" href="/assets/js/20.5b11fd5b.js"><link rel="prefetch" href="/assets/js/21.e5faf0b7.js"><link rel="prefetch" href="/assets/js/22.23137eae.js"><link rel="prefetch" href="/assets/js/24.20d474b3.js"><link rel="prefetch" href="/assets/js/25.6dc03c07.js"><link rel="prefetch" href="/assets/js/26.fcf5232b.js"><link rel="prefetch" href="/assets/js/27.6ee352c4.js"><link rel="prefetch" href="/assets/js/28.7534ba1e.js"><link rel="prefetch" href="/assets/js/29.352ed61c.js"><link rel="prefetch" href="/assets/js/3.2f315ac7.js"><link rel="prefetch" href="/assets/js/30.e5dbb079.js"><link rel="prefetch" href="/assets/js/31.b8562982.js"><link rel="prefetch" href="/assets/js/32.f3c8f832.js"><link rel="prefetch" href="/assets/js/33.5ca5188e.js"><link rel="prefetch" href="/assets/js/34.624e3116.js"><link rel="prefetch" href="/assets/js/35.35a86a7c.js"><link rel="prefetch" href="/assets/js/36.21f88fe5.js"><link rel="prefetch" href="/assets/js/37.f5b01c2c.js"><link rel="prefetch" href="/assets/js/38.79ed2093.js"><link rel="prefetch" href="/assets/js/39.687f8425.js"><link rel="prefetch" href="/assets/js/4.9af06e45.js"><link rel="prefetch" href="/assets/js/40.deaa2213.js"><link rel="prefetch" href="/assets/js/41.ede9f8e5.js"><link rel="prefetch" href="/assets/js/42.c48ff846.js"><link rel="prefetch" href="/assets/js/43.012e8b81.js"><link rel="prefetch" href="/assets/js/44.d7040c40.js"><link rel="prefetch" href="/assets/js/45.2805a83b.js"><link rel="prefetch" href="/assets/js/46.95a37284.js"><link rel="prefetch" href="/assets/js/47.d1c213db.js"><link rel="prefetch" href="/assets/js/48.00be6d02.js"><link rel="prefetch" href="/assets/js/49.3d722bd1.js"><link rel="prefetch" href="/assets/js/5.aace9ee0.js"><link rel="prefetch" href="/assets/js/50.d9fa2cde.js"><link rel="prefetch" href="/assets/js/51.e0aaa97a.js"><link rel="prefetch" href="/assets/js/52.a700a7a9.js"><link rel="prefetch" href="/assets/js/53.dbb93ca1.js"><link rel="prefetch" href="/assets/js/6.e0576ee1.js"><link rel="prefetch" href="/assets/js/7.4a4a967d.js"><link rel="prefetch" href="/assets/js/8.b7698a4a.js"><link rel="prefetch" href="/assets/js/9.6930a420.js">
    <link rel="stylesheet" href="/assets/css/0.styles.0ad39d54.css">
  </head>
  <body>
    <div id="app" data-server-rendered="true"><div class="theme-container"><header class="navbar"><div class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/" class="home-link router-link-active"><!----> <span class="site-name">若川的博客</span></a> <div class="links"><div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div> <nav class="nav-links can-hide"><div class="nav-item"><a href="https://image-static.segmentfault.com/355/182/3551821948-5df888aa1dc88_articlex" target="_blank" rel="noopener noreferrer" class="nav-link external">
  公众号：若川视野
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></div><div class="nav-item"><a href="/" class="nav-link">
  目录
</a></div><div class="nav-item"><a href="/about/" class="nav-link">
  关于我
</a></div><div class="nav-item"><a href="/poetry/2012-2016/" class="nav-link">
  曾经写的&quot;诗词&quot;
</a></div><div class="nav-item"><a href="https://github.com/lxchuan12/blog" target="_blank" rel="noopener noreferrer" class="nav-link external">
  Github
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></div><div class="nav-item"><a href="https://juejin.im/user/1415826704971918/posts" target="_blank" rel="noopener noreferrer" class="nav-link external">
  掘金
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></div><div class="nav-item"><a href="https://www.zhihu.com/people/lxchuan12/activities" target="_blank" rel="noopener noreferrer" class="nav-link external">
  知乎
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></div><div class="nav-item"><a href="https://www.yuque.com/lxchuan12/blog" target="_blank" rel="noopener noreferrer" class="nav-link external">
  语雀
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="其他" class="dropdown-title"><span class="title">其他</span> <span class="arrow down"></span></button> <button type="button" aria-label="其他" class="mobile-dropdown-title"><span class="title">其他</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="https://segmentfault.com/u/lxchuan12/articles" target="_blank" rel="noopener noreferrer" class="nav-link external">
  segmentFault
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-item"><!----> <a href="http://weibo.com/lxchuan12" target="_blank" rel="noopener noreferrer" class="nav-link external">
  微博
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-item"><!----> <a href="http://www.jianshu.com/users/83129d433d72/latest_articles" target="_blank" rel="noopener noreferrer" class="nav-link external">
  简书
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="友链" class="dropdown-title"><span class="title">友链</span> <span class="arrow down"></span></button> <button type="button" aria-label="友链" class="mobile-dropdown-title"><span class="title">友链</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="https://shanyue.tech" target="_blank" rel="noopener noreferrer" class="nav-link external">
  山月
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-item"><!----> <a href="http://lucifer.ren" target="_blank" rel="noopener noreferrer" class="nav-link external">
  lucifer
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-item"><!----> <a href="https://hungryturbo.com" target="_blank" rel="noopener noreferrer" class="nav-link external">
  童欧巴
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-item"><!----> <a href="https://www.scarsu.com/" target="_blank" rel="noopener noreferrer" class="nav-link external">
  scarsu
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-item"><!----> <a href="https://mtc.nofwl.com/" target="_blank" rel="noopener noreferrer" class="nav-link external">
  lencx的博客
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-item"><!----> <a href="https://coder.itclan.cn/" target="_blank" rel="noopener noreferrer" class="nav-link external">
  itclanCoder
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-item"><!----> <a href="https://ruizhengyun.cn" target="_blank" rel="noopener noreferrer" class="nav-link external">
  编程之上
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li></ul></div></div> <!----></nav></div></header> <div class="sidebar-mask"></div> <aside class="sidebar"><nav class="nav-links"><div class="nav-item"><a href="https://image-static.segmentfault.com/355/182/3551821948-5df888aa1dc88_articlex" target="_blank" rel="noopener noreferrer" class="nav-link external">
  公众号：若川视野
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></div><div class="nav-item"><a href="/" class="nav-link">
  目录
</a></div><div class="nav-item"><a href="/about/" class="nav-link">
  关于我
</a></div><div class="nav-item"><a href="/poetry/2012-2016/" class="nav-link">
  曾经写的&quot;诗词&quot;
</a></div><div class="nav-item"><a href="https://github.com/lxchuan12/blog" target="_blank" rel="noopener noreferrer" class="nav-link external">
  Github
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></div><div class="nav-item"><a href="https://juejin.im/user/1415826704971918/posts" target="_blank" rel="noopener noreferrer" class="nav-link external">
  掘金
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></div><div class="nav-item"><a href="https://www.zhihu.com/people/lxchuan12/activities" target="_blank" rel="noopener noreferrer" class="nav-link external">
  知乎
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></div><div class="nav-item"><a href="https://www.yuque.com/lxchuan12/blog" target="_blank" rel="noopener noreferrer" class="nav-link external">
  语雀
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="其他" class="dropdown-title"><span class="title">其他</span> <span class="arrow down"></span></button> <button type="button" aria-label="其他" class="mobile-dropdown-title"><span class="title">其他</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="https://segmentfault.com/u/lxchuan12/articles" target="_blank" rel="noopener noreferrer" class="nav-link external">
  segmentFault
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-item"><!----> <a href="http://weibo.com/lxchuan12" target="_blank" rel="noopener noreferrer" class="nav-link external">
  微博
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-item"><!----> <a href="http://www.jianshu.com/users/83129d433d72/latest_articles" target="_blank" rel="noopener noreferrer" class="nav-link external">
  简书
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="友链" class="dropdown-title"><span class="title">友链</span> <span class="arrow down"></span></button> <button type="button" aria-label="友链" class="mobile-dropdown-title"><span class="title">友链</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="https://shanyue.tech" target="_blank" rel="noopener noreferrer" class="nav-link external">
  山月
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-item"><!----> <a href="http://lucifer.ren" target="_blank" rel="noopener noreferrer" class="nav-link external">
  lucifer
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-item"><!----> <a href="https://hungryturbo.com" target="_blank" rel="noopener noreferrer" class="nav-link external">
  童欧巴
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-item"><!----> <a href="https://www.scarsu.com/" target="_blank" rel="noopener noreferrer" class="nav-link external">
  scarsu
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-item"><!----> <a href="https://mtc.nofwl.com/" target="_blank" rel="noopener noreferrer" class="nav-link external">
  lencx的博客
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-item"><!----> <a href="https://coder.itclan.cn/" target="_blank" rel="noopener noreferrer" class="nav-link external">
  itclanCoder
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-item"><!----> <a href="https://ruizhengyun.cn" target="_blank" rel="noopener noreferrer" class="nav-link external">
  编程之上
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li></ul></div></div> <!----></nav>  <ul class="sidebar-links"><li><a href="/" aria-current="page" class="sidebar-link">目录</a></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading open"><span>学习源码系列</span> <span class="arrow down"></span></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/redux/" class="sidebar-link">学习 redux 源码整体架构，深入理解 redux 及其中间件原理</a></li><li><a href="/koa/" class="sidebar-link">学习 koa 源码的整体架构，浅析koa洋葱模型原理和co原理</a></li><li><a href="/axios/" aria-current="page" class="active sidebar-link">学习 axios 源码整体架构，打造属于自己的请求库</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/axios/#_1-前言" class="sidebar-link">1. 前言</a></li><li class="sidebar-sub-header"><a href="/axios/#_2-chrome-和-vscode-调试-axios-源码方法" class="sidebar-link">2. chrome 和 vscode 调试 axios 源码方法</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/axios/#_2-1-chrome-调试浏览器环境的-axios" class="sidebar-link">2.1 chrome 调试浏览器环境的 axios</a></li><li class="sidebar-sub-header"><a href="/axios/#_2-2-vscode-调试-node-环境的-axios" class="sidebar-link">2.2 vscode 调试 node 环境的 axios</a></li></ul></li><li class="sidebar-sub-header"><a href="/axios/#_3-先看-axios-结构是怎样的" class="sidebar-link">3. 先看 axios 结构是怎样的</a></li><li class="sidebar-sub-header"><a href="/axios/#_4-axios-源码-初始化" class="sidebar-link">4. axios 源码 初始化</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/axios/#_4-1-lib-axios-js主文件" class="sidebar-link">4.1 lib/axios.js主文件</a></li><li class="sidebar-sub-header"><a href="/axios/#_4-2-核心构造函数-axios" class="sidebar-link">4.2 核心构造函数 Axios</a></li><li class="sidebar-sub-header"><a href="/axios/#_4-3-拦截器管理构造函数-interceptormanager" class="sidebar-link">4.3 拦截器管理构造函数 InterceptorManager</a></li></ul></li><li class="sidebar-sub-header"><a href="/axios/#_5-实例结合" class="sidebar-link">5. 实例结合</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/axios/#_5-1-先看调用栈流程" class="sidebar-link">5.1 先看调用栈流程</a></li><li class="sidebar-sub-header"><a href="/axios/#_5-2-axios-prototype-request-请求核心方法" class="sidebar-link">5.2 Axios.prototype.request 请求核心方法</a></li><li class="sidebar-sub-header"><a href="/axios/#_5-3-dispatchrequest-最终派发请求" class="sidebar-link">5.3 dispatchRequest 最终派发请求</a></li><li class="sidebar-sub-header"><a href="/axios/#_5-4-adapter-适配器-真正发送请求" class="sidebar-link">5.4 adapter 适配器 真正发送请求</a></li><li class="sidebar-sub-header"><a href="/axios/#_5-5-dispatchrequest-之-取消模块" class="sidebar-link">5.5 dispatchRequest 之 取消模块</a></li></ul></li><li class="sidebar-sub-header"><a href="/axios/#_6-对比其他请求库" class="sidebar-link">6. 对比其他请求库</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/axios/#_6-1-koajax" class="sidebar-link">6.1 KoAjax</a></li><li class="sidebar-sub-header"><a href="/axios/#_6-2-umi-request-阿里开源的请求库" class="sidebar-link">6.2 umi-request 阿里开源的请求库</a></li></ul></li><li class="sidebar-sub-header"><a href="/axios/#_7-总结" class="sidebar-link">7. 总结</a></li><li class="sidebar-sub-header"><a href="/axios/#推荐阅读" class="sidebar-link">推荐阅读</a></li><li class="sidebar-sub-header"><a href="/axios/#笔者另一个系列" class="sidebar-link">笔者另一个系列</a></li><li class="sidebar-sub-header"><a href="/axios/#关于" class="sidebar-link">关于</a></li><li class="sidebar-sub-header"><a href="/axios/#欢迎加微信交流-微信公众号" class="sidebar-link">欢迎加微信交流 微信公众号</a></li></ul></li><li><a href="/vuex/" class="sidebar-link">学习 vuex 源码整体架构，打造属于自己的状态管理库</a></li><li><a href="/sentry/" class="sidebar-link">学习 sentry 源码整体架构，打造属于自己的前端异常监控SDK</a></li><li><a href="/lodash/" class="sidebar-link">学习 lodash  源码整体架构，打造属于自己的函数式编程类库</a></li><li><a href="/underscore/" class="sidebar-link">学习underscore源码整体架构，打造属于自己的函数式编程类库</a></li><li><a href="/jquery/" class="sidebar-link">学习 jQuery 源码整体架构，打造属于自己的 js 类库</a></li></ul></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>面试官问系列</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>历史文章</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>杂文</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>曾经写的&quot;诗词&quot;</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>年度总结</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>关于</span> <span class="arrow right"></span></p> <!----></section></li></ul> </aside> <main class="page"> <div class="theme-default-content content__default"><h1 id="学习-axios-源码整体架构-打造属于自己的请求库"><a href="#学习-axios-源码整体架构-打造属于自己的请求库" class="header-anchor">#</a> 学习 axios 源码整体架构，打造属于自己的请求库</h1> <h2 id="_1-前言"><a href="#_1-前言" class="header-anchor">#</a> 1. 前言</h2> <blockquote><p>你好，我是<a href="https://lxchuan12.gitee.io" target="_blank" rel="noopener noreferrer">若川<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>，微信搜索<a href="https://mp.weixin.qq.com/s/c3hFML3XN9KCUetDOZd-DQ" target="_blank" rel="noopener noreferrer">「若川视野」<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>关注我，专注前端技术分享。欢迎加我微信<code>ruochuan12</code>，加群交流学习。</p></blockquote> <blockquote><p>这是<code>学习源码整体架构系列</code>第六篇。整体架构这词语好像有点大，姑且就算是源码整体结构吧，主要就是学习是代码整体结构，不深究其他不是主线的具体函数的实现。本篇文章学习的是实际仓库的代码。</p></blockquote> <blockquote><p><a href="https://github.com/lxchuan12/axios-analysis.git" target="_blank" rel="noopener noreferrer">本文仓库地址<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>：<code>git clone https://github.com/lxchuan12/axios-analysis.git</code></p></blockquote> <blockquote><p><strong>要是有人说到怎么读源码，正在读文章的你能推荐我的源码系列文章，那真是太好了</strong>。</p></blockquote> <p><code>学习源码整体架构系列</code>文章如下：</p> <blockquote><p>1.<a href="https://juejin.im/post/5d39d2cbf265da1bc23fbd42" target="_blank" rel="noopener noreferrer">学习 jQuery 源码整体架构，打造属于自己的 js 类库<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a><br>
2.<a href="https://juejin.im/post/5d4bf94de51d453bb13b65dc" target="_blank" rel="noopener noreferrer">学习 underscore 源码整体架构，打造属于自己的函数式编程类库<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a><br>
3.<a href="https://juejin.im/post/5d767e1d6fb9a06b032025ea" target="_blank" rel="noopener noreferrer">学习 lodash 源码整体架构，打造属于自己的函数式编程类库<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a><br>
4.<a href="https://juejin.im/post/5dba5a39e51d452a2378348a" target="_blank" rel="noopener noreferrer">学习 sentry 源码整体架构，打造属于自己的前端异常监控SDK<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a><br>
5.<a href="https://juejin.im/post/5dd4e61a6fb9a05a5c010af0" target="_blank" rel="noopener noreferrer">学习 vuex 源码整体架构，打造属于自己的状态管理库<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a><br>
6.<a href="https://juejin.im/post/5df349b5518825123751ba66" target="_blank" rel="noopener noreferrer">学习 axios 源码整体架构，打造属于自己的请求库<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a><br>
7.<a href="https://juejin.im/post/5e69925cf265da571e262fe6" target="_blank" rel="noopener noreferrer">学习 koa 源码的整体架构，浅析koa洋葱模型原理和co原理<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a><br>
8.<a href="https://juejin.im/post/5ee63b7d51882542fc6265ad" target="_blank" rel="noopener noreferrer">学习 redux 源码整体架构，深入理解 redux 及其中间件原理<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></p></blockquote> <p>感兴趣的读者可以点击阅读。<br>
其他源码计划中的有：<a href="https://github.com/lxchuan12/express-analysis" target="_blank" rel="noopener noreferrer"><code>express</code><span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>、<a href="https://github.com/lxchuan12/vue-router-analysis" target="_blank" rel="noopener noreferrer"><code>vue-rotuer</code><span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>、<a href="https://github.com/lxchuan12/react-redux-analysis" target="_blank" rel="noopener noreferrer"><code>react-redux</code><span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> 等源码，不知何时能写完（哭泣），欢迎持续关注我（若川）。</p> <p>源码类文章，一般阅读量不高。已经有能力看懂的，自己就看了。不想看，不敢看的就不会去看源码。<br>
所以我的文章，尽量写得让想看源码又不知道怎么看的读者能看懂。</p> <p>本文比较长，手机上阅读，可以划到有图的地方直接看文中的几张图即可。建议点赞或收藏后在电脑上阅读，按照文中调试方式自己调试或许更容易吸收消化。</p> <p><strong>导读</strong><br>
文章详细介绍了 <code>axios</code> 调试方法。详细介绍了 <code>axios</code> 构造函数，拦截器，取消等功能的实现。最后还对比了其他请求库。</p> <p>本文学习的版本是<code>v0.19.0</code>。克隆的官方仓库的<code>master</code>分支。
截至目前（2019年12月14日），最新一次<code>commit</code>是<code>2019-12-09 15:52 ZhaoXC</code> <code>dc4bc49673943e352</code>，<code>fix: fix ignore set withCredentials false (#2582)</code>。</p> <p>本文仓库在这里<a href="https://github.com/lxchuan12/axios-analysis" target="_blank" rel="noopener noreferrer">若川的 axios-analysis github 仓库<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>。求个<code>star</code>呀。</p> <p>如果你是求职者，项目写了运用了<code>axios</code>，面试官可能会问你：</p> <blockquote><p>1.为什么 <code>axios</code> 既可以当函数调用，也可以当对象使用，比如<code>axios({})</code>、<code>axios.get</code>。<br>
2.简述 <code>axios</code> 调用流程。<br>
3.有用过拦截器吗？原理是怎样的？<br>
4.有使用<code>axios</code>的取消功能吗？是怎么实现的？<br>
5.为什么支持浏览器中发送请求也支持<code>node</code>发送请求？<br>
诸如这类问题。</p></blockquote> <h2 id="_2-chrome-和-vscode-调试-axios-源码方法"><a href="#_2-chrome-和-vscode-调试-axios-源码方法" class="header-anchor">#</a> 2. chrome 和 vscode 调试 axios 源码方法</h2> <p>前不久，笔者在知乎回答了一个问题<a href="https://www.zhihu.com/question/350289336/answer/910970733" target="_blank" rel="noopener noreferrer">一年内的前端看不懂前端框架源码怎么办？<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>
推荐了一些资料，阅读量还不错，大家有兴趣可以看看。主要有四点：<br></p> <blockquote><p>1.借助调试<br>
2.搜索查阅相关高赞文章<br>
3.把不懂的地方记录下来，查阅相关文档<br>
4.总结<br></p></blockquote> <p>看源码，调试很重要，所以笔者详细写下 <code>axios</code> 源码调试方法，帮助一些可能不知道如何调试的读者。</p> <h3 id="_2-1-chrome-调试浏览器环境的-axios"><a href="#_2-1-chrome-调试浏览器环境的-axios" class="header-anchor">#</a> 2.1 chrome 调试浏览器环境的 axios</h3> <p>调试方法</p> <p><code>axios</code>打包后有<code>sourcemap</code>文件。</p> <div class="language-bash extra-class"><pre class="language-bash"><code><span class="token comment"># 可以克隆笔者的这个仓库代码</span>
<span class="token function">git</span> clone https://github.com/lxchuan12/axios-analysis.git
<span class="token builtin class-name">cd</span> axios-analaysis/axios
<span class="token function">npm</span> <span class="token function">install</span>
<span class="token function">npm</span> start
<span class="token comment"># open [http://localhost:3000](http://localhost:3000)</span>
<span class="token comment"># chrome F12 source 控制面板  webpack//   .  lib 目录下，根据情况自行断点调试</span>
</code></pre></div><p>本文就是通过上述的例子<code>axios/sandbox/client.html</code>来调试的。</p> <p>顺便简单提下调试<code>example</code>的例子，虽然文章最开始时写了这部分，后来又删了，最后想想还是写下。</p> <p>找到文件<code>axios/examples/server.js</code>，修改代码如下：</p> <div class="language-js extra-class"><pre class="language-js"><code>server <span class="token operator">=</span> http<span class="token punctuation">.</span><span class="token function">createServer</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">req<span class="token punctuation">,</span> res</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">var</span> url <span class="token operator">=</span> req<span class="token punctuation">.</span>url<span class="token punctuation">;</span>
  <span class="token comment">// 调试 examples</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>url<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token comment">// Process axios itself</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">axios\.min\.js$</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">.</span><span class="token function">test</span><span class="token punctuation">(</span>url<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">// 原来的代码 是 axios.min.js</span>
    <span class="token comment">// pipeFileToResponse(res, '../dist/axios.min.js', 'text/javascript');</span>
    <span class="token function">pipeFileToResponse</span><span class="token punctuation">(</span>res<span class="token punctuation">,</span> <span class="token string">'../dist/axios.js'</span><span class="token punctuation">,</span> <span class="token string">'text/javascript'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
  <span class="token comment">// 原来的代码 是 axios.min.map</span>
  <span class="token comment">// if (/axios\.min.map$/.test(url)) {</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">axios\.map$</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">.</span><span class="token function">test</span><span class="token punctuation">(</span>url<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">// 原来的代码 是 axios.min.map</span>
    <span class="token comment">// pipeFileToResponse(res, '../dist/axios.min.map', 'text/javascript');</span>
    <span class="token function">pipeFileToResponse</span><span class="token punctuation">(</span>res<span class="token punctuation">,</span> <span class="token string">'../dist/axios.map'</span><span class="token punctuation">,</span> <span class="token string">'text/javascript'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><div class="language-bash extra-class"><pre class="language-bash"><code><span class="token comment"># 上述安装好依赖后</span>
<span class="token comment"># npm run examples 不能同时开启，默认都是3000端口</span>
<span class="token comment"># 可以指定端口 5000</span>
<span class="token comment"># npm run examples ===  node ./examples/server.js</span>
node ./examples/server.js -p <span class="token number">5000</span>
</code></pre></div><p>打开<a href="http://localhost:5000" target="_blank" rel="noopener noreferrer">http://localhost:5000<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>，然后就可以开心的在<code>Chrome</code>浏览器中调试<code>examples</code>里的例子了。</p> <p><code>axios</code> 是支持 <code>node</code> 环境发送请求的。接下来看如何用 <code>vscode</code> 调试 <code>node</code> 环境下的<code>axios</code>。</p> <h3 id="_2-2-vscode-调试-node-环境的-axios"><a href="#_2-2-vscode-调试-node-环境的-axios" class="header-anchor">#</a> 2.2 vscode 调试 node 环境的 axios</h3> <p>在根目录下 <code>axios-analysis/</code>
创建<code>.vscode/launch.json</code>文件如下：</p> <div class="language-json extra-class"><pre class="language-json"><code><span class="token punctuation">{</span>
    <span class="token comment">// 使用 IntelliSense 了解相关属性。</span>
    <span class="token comment">// 悬停以查看现有属性的描述。</span>
    <span class="token comment">// 欲了解更多信息，请访问: https://go.microsoft.com/fwlink/?linkid=830387</span>
    <span class="token property">&quot;version&quot;</span><span class="token operator">:</span> <span class="token string">&quot;0.2.0&quot;</span><span class="token punctuation">,</span>
    <span class="token property">&quot;configurations&quot;</span><span class="token operator">:</span> <span class="token punctuation">[</span>
        <span class="token punctuation">{</span>
            <span class="token property">&quot;type&quot;</span><span class="token operator">:</span> <span class="token string">&quot;node&quot;</span><span class="token punctuation">,</span>
            <span class="token property">&quot;request&quot;</span><span class="token operator">:</span> <span class="token string">&quot;launch&quot;</span><span class="token punctuation">,</span>
            <span class="token property">&quot;name&quot;</span><span class="token operator">:</span> <span class="token string">&quot;Launch Program&quot;</span><span class="token punctuation">,</span>
            <span class="token property">&quot;program&quot;</span><span class="token operator">:</span> <span class="token string">&quot;${workspaceFolder}/axios/sandbox/client.js&quot;</span><span class="token punctuation">,</span>
            <span class="token property">&quot;skipFiles&quot;</span><span class="token operator">:</span> <span class="token punctuation">[</span>
                <span class="token string">&quot;&lt;node_internals&gt;/**&quot;</span>
            <span class="token punctuation">]</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">]</span>
<span class="token punctuation">}</span>
</code></pre></div><p>按<code>F5</code>开始调试即可，按照自己的情况，单步跳过<code>（F10）</code>、单步调试<code>（F11）</code>断点调试。</p> <p>其实开源项目一般都有贡献指南<code>axios/CONTRIBUTING.md</code>，笔者只是把这个指南的基础上修改为引用<code>sourcemap</code>的文件可调试。</p> <h2 id="_3-先看-axios-结构是怎样的"><a href="#_3-先看-axios-结构是怎样的" class="header-anchor">#</a> 3. 先看 axios 结构是怎样的</h2> <div class="language-bash extra-class"><pre class="language-bash"><code><span class="token function">git</span> clone https://github.com/lxchuan12/axios-analysis.git
<span class="token builtin class-name">cd</span> axios-analaysis/axios
<span class="token function">npm</span> <span class="token function">install</span>
<span class="token function">npm</span> start
</code></pre></div><p>按照上文说的调试方法， <code>npm start</code> 后，直接在 <code>chrome</code> 浏览器中调试。
打开 <a href="http://localhost:3000" target="_blank" rel="noopener noreferrer">http://localhost:3000<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>，在控制台打印出<code>axios</code>，估计很多人都没打印出来看过。</p> <div class="language-js extra-class"><pre class="language-js"><code>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token punctuation">{</span>axios<span class="token operator">:</span> axios<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>层层点开来看，<code>axios</code> 的结构是怎样的，先有一个大概印象。</p> <p>笔者画了一张比较详细的图表示。</p> <p><img src="/assets/img/axios-instance.e915a96a.png" alt="axios 结构关系图"></p> <p>看完结构图，如果看过<code>jQuery</code>、<code>underscore</code>和<code>lodash</code>源码，会发现其实跟<code>axios</code>源码设计类似。</p> <p><code>jQuery</code> 别名 <code>$</code>，<code>underscore</code> <code>loadsh</code> 别名 <code>_</code> 也既是函数，也是对象。比如<code>jQuery</code>使用方式。<code>$('#id')</code>, <code>$.ajax</code>。</p> <p>接下来看具体源码的实现。可以跟着断点调试一下。</p> <p><strong>断点调试要领：</strong><br> <strong>赋值语句可以一步跳过，看返回值即可，后续详细再看。</strong><br> <strong>函数执行需要断点跟着看，也可以结合注释和上下文倒推这个函数做了什么。</strong><br></p> <h2 id="_4-axios-源码-初始化"><a href="#_4-axios-源码-初始化" class="header-anchor">#</a> 4. axios 源码 初始化</h2> <p>看源码第一步，先看<code>package.json</code>。一般都会申明 <code>main</code> 主入口文件。</p> <div class="language-json extra-class"><pre class="language-json"><code><span class="token comment">// package.json</span>
<span class="token punctuation">{</span>
  <span class="token property">&quot;name&quot;</span><span class="token operator">:</span> <span class="token string">&quot;axios&quot;</span><span class="token punctuation">,</span>
  <span class="token property">&quot;version&quot;</span><span class="token operator">:</span> <span class="token string">&quot;0.19.0&quot;</span><span class="token punctuation">,</span>
  <span class="token property">&quot;description&quot;</span><span class="token operator">:</span> <span class="token string">&quot;Promise based HTTP client for the browser and node.js&quot;</span><span class="token punctuation">,</span>
  <span class="token property">&quot;main&quot;</span><span class="token operator">:</span> <span class="token string">&quot;index.js&quot;</span><span class="token punctuation">,</span>
  <span class="token comment">// ...</span>
<span class="token punctuation">}</span>
</code></pre></div><p>主入口文件</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// index.js</span>
module<span class="token punctuation">.</span>exports <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'./lib/axios'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><h3 id="_4-1-lib-axios-js主文件"><a href="#_4-1-lib-axios-js主文件" class="header-anchor">#</a> 4.1 <code>lib/axios.js</code>主文件</h3> <p><code>axios.js</code>文件 代码相对比较多。分为三部分展开叙述。</p> <blockquote><ol><li>第一部分：引入一些工具函数<code>utils</code>、<code>Axios</code>构造函数、默认配置<code>defaults</code>等。<br></li> <li>第二部分：是生成实例对象 <code>axios</code>、<code>axios.Axios</code>、<code>axios.create</code>等。<br></li> <li>第三部分取消相关API实现，还有<code>all</code>、<code>spread</code>、导出等实现。<br></li></ol></blockquote> <h4 id="_4-1-1-第一部分"><a href="#_4-1-1-第一部分" class="header-anchor">#</a> 4.1.1 第一部分</h4> <p>引入一些工具函数<code>utils</code>、<code>Axios</code>构造函数、默认配置<code>defaults</code>等。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// 第一部分：</span>
<span class="token comment">// lib/axios</span>
<span class="token comment">// 严格模式</span>
<span class="token string">'use strict'</span><span class="token punctuation">;</span>
<span class="token comment">// 引入 utils 对象，有很多工具方法。</span>
<span class="token keyword">var</span> utils <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'./utils'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 引入 bind 方法</span>
<span class="token keyword">var</span> bind <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'./helpers/bind'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 核心构造函数 Axios</span>
<span class="token keyword">var</span> Axios <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'./core/Axios'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 合并配置方法</span>
<span class="token keyword">var</span> mergeConfig <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'./core/mergeConfig'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 引入默认配置</span>
<span class="token keyword">var</span> defaults <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'./defaults'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><h4 id="_4-1-2-第二部分"><a href="#_4-1-2-第二部分" class="header-anchor">#</a> 4.1.2 第二部分</h4> <p>是生成实例对象 <code>axios</code>、<code>axios.Axios</code>、<code>axios.create</code>等。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">/**
 * Create an instance of Axios
 *
 * @param {Object} defaultConfig The default config for the instance
 * @return {Axios} A new instance of Axios
 */</span>
<span class="token keyword">function</span> <span class="token function">createInstance</span><span class="token punctuation">(</span><span class="token parameter">defaultConfig</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// new 一个 Axios 生成实例对象</span>
  <span class="token keyword">var</span> context <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Axios</span><span class="token punctuation">(</span>defaultConfig<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token comment">// bind 返回一个新的 wrap 函数，</span>
  <span class="token comment">// 也就是为什么调用 axios 是调用 Axios.prototype.request 函数的原因</span>
  <span class="token keyword">var</span> instance <span class="token operator">=</span> <span class="token function">bind</span><span class="token punctuation">(</span><span class="token class-name">Axios</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span>request<span class="token punctuation">,</span> context<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token comment">// Copy axios.prototype to instance</span>
  <span class="token comment">// 复制 Axios.prototype 到实例上。</span>
  <span class="token comment">// 也就是为什么 有 axios.get 等别名方法，</span>
  <span class="token comment">// 且调用的是 Axios.prototype.get 等别名方法。</span>
  utils<span class="token punctuation">.</span><span class="token function">extend</span><span class="token punctuation">(</span>instance<span class="token punctuation">,</span> <span class="token class-name">Axios</span><span class="token punctuation">.</span>prototype<span class="token punctuation">,</span> context<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token comment">// Copy context to instance</span>
  <span class="token comment">// 复制 context 到 intance 实例</span>
  <span class="token comment">// 也就是为什么默认配置 axios.defaults 和拦截器  axios.interceptors 可以使用的原因</span>
  <span class="token comment">// 其实是new Axios().defaults 和 new Axios().interceptors</span>
  utils<span class="token punctuation">.</span><span class="token function">extend</span><span class="token punctuation">(</span>instance<span class="token punctuation">,</span> context<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token comment">// 最后返回实例对象，以上代码，在上文的图中都有体现。这时可以仔细看下上图。</span>
  <span class="token keyword">return</span> instance<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">// Create the default instance to be exported</span>
<span class="token comment">// 导出 创建默认实例</span>
<span class="token keyword">var</span> axios <span class="token operator">=</span> <span class="token function">createInstance</span><span class="token punctuation">(</span>defaults<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Expose Axios class to allow class inheritance</span>
<span class="token comment">// 暴露 Axios class 允许 class 继承 也就是可以 new axios.Axios()</span>
<span class="token comment">// 但  axios 文档中 并没有提到这个，我们平时也用得少。</span>
axios<span class="token punctuation">.</span>Axios <span class="token operator">=</span> Axios<span class="token punctuation">;</span>

<span class="token comment">// Factory for creating new instances</span>
<span class="token comment">// 工厂模式 创建新的实例 用户可以自定义一些参数</span>
axios<span class="token punctuation">.</span><span class="token function-variable function">create</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token function">create</span><span class="token punctuation">(</span><span class="token parameter">instanceConfig</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token function">createInstance</span><span class="token punctuation">(</span><span class="token function">mergeConfig</span><span class="token punctuation">(</span>axios<span class="token punctuation">.</span>defaults<span class="token punctuation">,</span> instanceConfig<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre></div><p>这里简述下工厂模式。<code>axios.create</code>，也就是用户不需要知道内部是怎么实现的。<br>
举个生活的例子，我们买手机，不需要知道手机是怎么做的，就是工厂模式。<br>
看完第二部分，里面涉及几个工具函数，如<code>bind</code>、<code>extend</code>。接下来讲述这几个工具方法。<br></p> <h4 id="_4-1-3-工具方法之-bind"><a href="#_4-1-3-工具方法之-bind" class="header-anchor">#</a> 4.1.3 工具方法之 bind</h4> <p><code>axios/lib/helpers/bind.js</code></p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token string">'use strict'</span><span class="token punctuation">;</span>
<span class="token comment">// 返回一个新的函数 wrap</span>
module<span class="token punctuation">.</span><span class="token function-variable function">exports</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token function">bind</span><span class="token punctuation">(</span><span class="token parameter">fn<span class="token punctuation">,</span> thisArg</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token keyword">function</span> <span class="token function">wrap</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">var</span> args <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Array</span><span class="token punctuation">(</span>arguments<span class="token punctuation">.</span>length<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">var</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> args<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      args<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">=</span> arguments<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token comment">// 把 argument 对象放在数组 args 里</span>
    <span class="token keyword">return</span> <span class="token function">fn</span><span class="token punctuation">.</span><span class="token function">apply</span><span class="token punctuation">(</span>thisArg<span class="token punctuation">,</span> args<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre></div><p>传递两个参数函数和<code>thisArg</code>指向。<br>
把参数<code>arguments</code>生成数组，最后调用返回参数结构。<br>
其实现在 <code>apply</code> 支持 <code>arguments</code>这样的类数组对象了，不需要手动转数组。<br>
那么为啥作者要转数组，为了性能？当时不支持？抑或是作者不知道？这就不得而知了。有读者知道欢迎评论区告诉笔者呀。<br></p> <p>关于<code>apply</code>、<code>call</code>和<code>bind</code>等不是很熟悉的读者，可以看笔者的另一个<code>面试官问系列</code>。<br> <a href="https://juejin.im/post/5bec4183f265da616b1044d7" target="_blank" rel="noopener noreferrer">面试官问：能否模拟实现JS的bind方法<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a><br></p> <p>举个例子</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">fn</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">.</span><span class="token function">apply</span><span class="token punctuation">(</span>console<span class="token punctuation">,</span> arguments<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token function">fn</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token punctuation">,</span><span class="token number">5</span><span class="token punctuation">,</span><span class="token number">6</span><span class="token punctuation">,</span> <span class="token string">'若川'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 1 2 3 4 5 6 '若川'</span>
</code></pre></div><h4 id="_4-1-4-工具方法之-utils-extend"><a href="#_4-1-4-工具方法之-utils-extend" class="header-anchor">#</a> 4.1.4 工具方法之 utils.extend</h4> <p><code>axios/lib/utils.js</code></p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">extend</span><span class="token punctuation">(</span><span class="token parameter">a<span class="token punctuation">,</span> b<span class="token punctuation">,</span> thisArg</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token function">forEach</span><span class="token punctuation">(</span>b<span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token function">assignValue</span><span class="token punctuation">(</span><span class="token parameter">val<span class="token punctuation">,</span> key</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>thisArg <span class="token operator">&amp;&amp;</span> <span class="token keyword">typeof</span> val <span class="token operator">===</span> <span class="token string">'function'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      a<span class="token punctuation">[</span>key<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">bind</span><span class="token punctuation">(</span>val<span class="token punctuation">,</span> thisArg<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
      a<span class="token punctuation">[</span>key<span class="token punctuation">]</span> <span class="token operator">=</span> val<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> a<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p>其实就是遍历参数 <code>b</code> 对象，复制到 <code>a</code> 对象上，如果是函数就是则用 <code>bind</code> 调用。</p> <h4 id="_4-1-5-工具方法之-utils-foreach"><a href="#_4-1-5-工具方法之-utils-foreach" class="header-anchor">#</a> 4.1.5 工具方法之 utils.forEach</h4> <p><code>axios/lib/utils.js</code></p> <p>遍历数组和对象。设计模式称之为迭代器模式。很多源码都有类似这样的遍历函数。比如大家熟知的<code>jQuery</code> <code>$.each</code>。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">/**
 * @param {Object|Array} obj The object to iterate
 * @param {Function} fn The callback to invoke for each item
 */</span>
<span class="token keyword">function</span> <span class="token function">forEach</span><span class="token punctuation">(</span><span class="token parameter">obj<span class="token punctuation">,</span> fn</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// Don't bother if no value provided</span>
  <span class="token comment">// 判断 null 和 undefined 直接返回</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>obj <span class="token operator">===</span> <span class="token keyword">null</span> <span class="token operator">||</span> <span class="token keyword">typeof</span> obj <span class="token operator">===</span> <span class="token string">'undefined'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token comment">// Force an array if not already something iterable</span>
  <span class="token comment">// 如果不是对象，放在数组里。</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">typeof</span> obj <span class="token operator">!==</span> <span class="token string">'object'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">/*eslint no-param-reassign:0*/</span>
    obj <span class="token operator">=</span> <span class="token punctuation">[</span>obj<span class="token punctuation">]</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token comment">// 是数组 则用for 循环，调用 fn 函数。参数类似 Array.prototype.forEach 的前三个参数。</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">isArray</span><span class="token punctuation">(</span>obj<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">// Iterate over array values</span>
    <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">var</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">,</span> l <span class="token operator">=</span> obj<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i <span class="token operator">&lt;</span> l<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token function">fn</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">,</span> obj<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">,</span> i<span class="token punctuation">,</span> obj<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
    <span class="token comment">// Iterate over object keys</span>
    <span class="token comment">// 用 for in 遍历对象，但 for in 会遍历原型链上可遍历的属性。</span>
    <span class="token comment">// 所以用 hasOwnProperty 来过滤自身属性了。</span>
    <span class="token comment">// 其实也可以用Object.keys来遍历，它不遍历原型链上可遍历的属性。</span>
    <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">var</span> key <span class="token keyword">in</span> obj<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name">Object</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function">hasOwnProperty</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span>obj<span class="token punctuation">,</span> key<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token function">fn</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">,</span> obj<span class="token punctuation">[</span>key<span class="token punctuation">]</span><span class="token punctuation">,</span> key<span class="token punctuation">,</span> obj<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><p>如果对<code>Object</code>相关的<code>API</code>不熟悉，可以查看笔者之前写过的一篇文章。<a href="https://lxchuan12.gitee.io/js-object-api/" target="_blank" rel="noopener noreferrer">JavaScript 对象所有API解析<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></p> <h4 id="_4-1-6-第三部分"><a href="#_4-1-6-第三部分" class="header-anchor">#</a> 4.1.6 第三部分</h4> <p>取消相关API实现，还有<code>all</code>、<code>spread</code>、导出等实现。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// Expose Cancel &amp; CancelToken</span>
<span class="token comment">// 导出 Cancel 和 CancelToken</span>
axios<span class="token punctuation">.</span>Cancel <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'./cancel/Cancel'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
axios<span class="token punctuation">.</span>CancelToken <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'./cancel/CancelToken'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
axios<span class="token punctuation">.</span>isCancel <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'./cancel/isCancel'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// Expose all/spread</span>
<span class="token comment">// 导出 all 和 spread API</span>
axios<span class="token punctuation">.</span><span class="token function-variable function">all</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token function">all</span><span class="token punctuation">(</span><span class="token parameter">promises</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> Promise<span class="token punctuation">.</span><span class="token function">all</span><span class="token punctuation">(</span>promises<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
axios<span class="token punctuation">.</span>spread <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'./helpers/spread'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

module<span class="token punctuation">.</span>exports <span class="token operator">=</span> axios<span class="token punctuation">;</span>

<span class="token comment">// Allow use of default import syntax in TypeScript</span>
<span class="token comment">// 也就是可以以下方式引入</span>
<span class="token comment">// import axios from 'axios';</span>
module<span class="token punctuation">.</span>exports<span class="token punctuation">.</span>default <span class="token operator">=</span> axios<span class="token punctuation">;</span>
</code></pre></div><p>这里介绍下 <code>spread</code>，取消的<code>API</code>暂时不做分析，后文再详细分析。</p> <p>假设你有这样的需求。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">f</span><span class="token punctuation">(</span><span class="token parameter">x<span class="token punctuation">,</span> y<span class="token punctuation">,</span> z</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
<span class="token keyword">var</span> args <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token function">f</span><span class="token punctuation">.</span><span class="token function">apply</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">,</span> args<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>那么可以用<code>spread</code>方法。用法：</p> <div class="language-js extra-class"><pre class="language-js"><code>axios<span class="token punctuation">.</span><span class="token function">spread</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">x<span class="token punctuation">,</span> y<span class="token punctuation">,</span> z</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>实现也比较简单。源码实现：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">/**
 * @param {Function} callback
 * @returns {Function}
 */</span>
module<span class="token punctuation">.</span><span class="token function-variable function">exports</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token function">spread</span><span class="token punctuation">(</span><span class="token parameter">callback</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token keyword">function</span> <span class="token function">wrap</span><span class="token punctuation">(</span><span class="token parameter">arr</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token function">callback</span><span class="token punctuation">.</span><span class="token function">apply</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">,</span> arr<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre></div><p>上文<code>var context = new Axios(defaultConfig);</code>，接下来介绍核心构造函数<code>Axios</code>。</p> <h3 id="_4-2-核心构造函数-axios"><a href="#_4-2-核心构造函数-axios" class="header-anchor">#</a> 4.2 核心构造函数 Axios</h3> <p><code>axios/lib/core/Axios.js</code></p> <p>构造函数<code>Axios</code>。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">Axios</span><span class="token punctuation">(</span><span class="token parameter">instanceConfig</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// 默认参数</span>
  <span class="token keyword">this</span><span class="token punctuation">.</span>defaults <span class="token operator">=</span> instanceConfig<span class="token punctuation">;</span>
  <span class="token comment">// 拦截器 请求和响应拦截器</span>
  <span class="token keyword">this</span><span class="token punctuation">.</span>interceptors <span class="token operator">=</span> <span class="token punctuation">{</span>
    request<span class="token operator">:</span> <span class="token keyword">new</span> <span class="token class-name">InterceptorManager</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    response<span class="token operator">:</span> <span class="token keyword">new</span> <span class="token class-name">InterceptorManager</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><div class="language-js extra-class"><pre class="language-js"><code><span class="token class-name">Axios</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function-variable function">request</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">config</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
  <span class="token comment">// 省略，这个是核心方法，后文结合例子详细描述</span>
  <span class="token comment">// code ...</span>
  <span class="token keyword">var</span> promise <span class="token operator">=</span> Promise<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span>config<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token comment">// code ...</span>
  <span class="token keyword">return</span> promise<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">// 这是获取 Uri 的函数，这里省略</span>
<span class="token class-name">Axios</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function-variable function">getUri</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span><span class="token punctuation">}</span>
<span class="token comment">// 提供一些请求方法的别名</span>
<span class="token comment">// Provide aliases for supported request methods</span>
<span class="token comment">// 遍历执行</span>
<span class="token comment">// 也就是为啥我们可以 axios.get 等别名的方式调用，而且调用的是 Axios.prototype.request 方法</span>
<span class="token comment">// 这个也在上面的 axios 结构图上有所体现。</span>
utils<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'delete'</span><span class="token punctuation">,</span> <span class="token string">'get'</span><span class="token punctuation">,</span> <span class="token string">'head'</span><span class="token punctuation">,</span> <span class="token string">'options'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token function">forEachMethodNoData</span><span class="token punctuation">(</span><span class="token parameter">method</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">/*eslint func-names:0*/</span>
  <span class="token class-name">Axios</span><span class="token punctuation">.</span>prototype<span class="token punctuation">[</span>method<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">url<span class="token punctuation">,</span> config</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">request</span><span class="token punctuation">(</span>utils<span class="token punctuation">.</span><span class="token function">merge</span><span class="token punctuation">(</span>config <span class="token operator">||</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
      method<span class="token operator">:</span> method<span class="token punctuation">,</span>
      url<span class="token operator">:</span> url
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

utils<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'post'</span><span class="token punctuation">,</span> <span class="token string">'put'</span><span class="token punctuation">,</span> <span class="token string">'patch'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token function">forEachMethodWithData</span><span class="token punctuation">(</span><span class="token parameter">method</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">/*eslint func-names:0*/</span>
  <span class="token class-name">Axios</span><span class="token punctuation">.</span>prototype<span class="token punctuation">[</span>method<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">url<span class="token punctuation">,</span> data<span class="token punctuation">,</span> config</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">request</span><span class="token punctuation">(</span>utils<span class="token punctuation">.</span><span class="token function">merge</span><span class="token punctuation">(</span>config <span class="token operator">||</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
      method<span class="token operator">:</span> method<span class="token punctuation">,</span>
      url<span class="token operator">:</span> url<span class="token punctuation">,</span>
      data<span class="token operator">:</span> data
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

module<span class="token punctuation">.</span>exports <span class="token operator">=</span> Axios<span class="token punctuation">;</span>
</code></pre></div><p>接下来看拦截器部分。</p> <h3 id="_4-3-拦截器管理构造函数-interceptormanager"><a href="#_4-3-拦截器管理构造函数-interceptormanager" class="header-anchor">#</a> 4.3 拦截器管理构造函数 InterceptorManager</h3> <p>请求前拦截，和请求后拦截。<br>
在<code>Axios.prototype.request</code>函数里使用，具体怎么实现的拦截的，后文配合例子详细讲述。<br></p> <p><a href="https://github.com/axios/axios#interceptors" target="_blank" rel="noopener noreferrer">axios github 仓库 拦截器文档<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></p> <p>如何使用：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// Add a request interceptor</span>
<span class="token comment">// 添加请求前拦截器</span>
axios<span class="token punctuation">.</span>interceptors<span class="token punctuation">.</span>request<span class="token punctuation">.</span><span class="token function">use</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">config</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// Do something before request is sent</span>
  <span class="token keyword">return</span> config<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">error</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// Do something with request error</span>
  <span class="token keyword">return</span> Promise<span class="token punctuation">.</span><span class="token function">reject</span><span class="token punctuation">(</span>error<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// Add a response interceptor</span>
<span class="token comment">// 添加请求后拦截器</span>
axios<span class="token punctuation">.</span>interceptors<span class="token punctuation">.</span>response<span class="token punctuation">.</span><span class="token function">use</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">response</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// Any status code that lie within the range of 2xx cause this function to trigger</span>
  <span class="token comment">// Do something with response data</span>
  <span class="token keyword">return</span> response<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">error</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// Any status codes that falls outside the range of 2xx cause this function to trigger</span>
  <span class="token comment">// Do something with response error</span>
  <span class="token keyword">return</span> Promise<span class="token punctuation">.</span><span class="token function">reject</span><span class="token punctuation">(</span>error<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>如果想把拦截器移除，可以用<code>eject</code>方法。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> myInterceptor <span class="token operator">=</span> axios<span class="token punctuation">.</span>interceptors<span class="token punctuation">.</span>request<span class="token punctuation">.</span><span class="token function">use</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token comment">/*...*/</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
axios<span class="token punctuation">.</span>interceptors<span class="token punctuation">.</span>request<span class="token punctuation">.</span><span class="token function">eject</span><span class="token punctuation">(</span>myInterceptor<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>拦截器也可以添加自定义的实例上。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> instance <span class="token operator">=</span> axios<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
instance<span class="token punctuation">.</span>interceptors<span class="token punctuation">.</span>request<span class="token punctuation">.</span><span class="token function">use</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token comment">/*...*/</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>源码实现：</p> <p>构造函数，<code>handles</code> 用于存储拦截器函数。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">InterceptorManager</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">this</span><span class="token punctuation">.</span>handlers <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p>接下来声明了三个方法：使用、移除、遍历。</p> <h4 id="_4-3-1-interceptormanager-prototype-use-使用"><a href="#_4-3-1-interceptormanager-prototype-use-使用" class="header-anchor">#</a> 4.3.1 InterceptorManager.prototype.use 使用</h4> <p>传递两个函数作为参数，数组中的一项存储的是<code>{fulfilled: function(){}, rejected: function(){}}</code>。返回数字 <code>ID</code>，用于移除拦截器。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">/**
 * @param {Function} fulfilled The function to handle `then` for a `Promise`
 * @param {Function} rejected The function to handle `reject` for a `Promise`
 *
 * @return {Number} 返回ID 是为了用 eject 移除
 */</span>
<span class="token class-name">InterceptorManager</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function-variable function">use</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token function">use</span><span class="token punctuation">(</span><span class="token parameter">fulfilled<span class="token punctuation">,</span> rejected</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">this</span><span class="token punctuation">.</span>handlers<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    fulfilled<span class="token operator">:</span> fulfilled<span class="token punctuation">,</span>
    rejected<span class="token operator">:</span> rejected
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>handlers<span class="token punctuation">.</span>length <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre></div><h4 id="_4-3-2-interceptormanager-prototype-eject-移除"><a href="#_4-3-2-interceptormanager-prototype-eject-移除" class="header-anchor">#</a> 4.3.2 InterceptorManager.prototype.eject 移除</h4> <p>根据 <code>use</code> 返回的 <code>ID</code> 移除 拦截器。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">/**
 * @param {Number} id The ID that was returned by `use`
 */</span>
<span class="token class-name">InterceptorManager</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function-variable function">eject</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token function">eject</span><span class="token punctuation">(</span><span class="token parameter">id</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>handlers<span class="token punctuation">[</span>id<span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>handlers<span class="token punctuation">[</span>id<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre></div><p>有点类似定时器<code>setTimeout</code> 和 <code>setInterval</code>，返回值是<code>id</code>。用<code>clearTimeout</code> 和<code>clearInterval</code>来清除定时器。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// 提一下 定时器回调函数是可以传参的，返回值 timer 是数字</span>
<span class="token keyword">var</span> timer <span class="token operator">=</span> <span class="token function">setInterval</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">name</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">1000</span><span class="token punctuation">,</span> <span class="token string">'若川'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>timer<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 数字 ID</span>
<span class="token comment">// 在控制台等会再输入执行这句，定时器就被清除了</span>
<span class="token function">clearInterval</span><span class="token punctuation">(</span>timer<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><h4 id="_4-3-3-interceptormanager-prototype-foreach-遍历"><a href="#_4-3-3-interceptormanager-prototype-foreach-遍历" class="header-anchor">#</a> 4.3.3 InterceptorManager.prototype.forEach 遍历</h4> <p>遍历执行所有拦截器，传递一个回调函数（每一个拦截器函数作为参数）调用，被移除的一项是<code>null</code>，所以不会执行，也就达到了移除的效果。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">/**
 * @param {Function} fn The function to call for each interceptor
 */</span>
<span class="token class-name">InterceptorManager</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function-variable function">forEach</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token function">forEach</span><span class="token punctuation">(</span><span class="token parameter">fn</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  utils<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>handlers<span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token function">forEachHandler</span><span class="token punctuation">(</span><span class="token parameter">h</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>h <span class="token operator">!==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token function">fn</span><span class="token punctuation">(</span>h<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre></div><h2 id="_5-实例结合"><a href="#_5-实例结合" class="header-anchor">#</a> 5. 实例结合</h2> <p>上文叙述的调试时运行<code>npm start</code> 是用<code>axios/sandbox/client.html</code>路径的文件作为示例的，读者可以自行调试。</p> <p>以下是一段这个文件中的代码。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token function">axios</span><span class="token punctuation">(</span>options<span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">res</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  response<span class="token punctuation">.</span>innerHTML <span class="token operator">=</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span>res<span class="token punctuation">.</span>data<span class="token punctuation">,</span> <span class="token keyword">null</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">res</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  response<span class="token punctuation">.</span>innerHTML <span class="token operator">=</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span>res<span class="token punctuation">.</span>data<span class="token punctuation">,</span> <span class="token keyword">null</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><h3 id="_5-1-先看调用栈流程"><a href="#_5-1-先看调用栈流程" class="header-anchor">#</a> 5.1 先看调用栈流程</h3> <p>如果不想一步步调试，有个偷巧的方法。<br>
知道 <code>axios</code> 使用了<code>XMLHttpRequest</code>。<br>
可以在项目中搜索：<code>new XMLHttpRequest</code>。<br>
定位到文件 <code>axios/lib/adapters/xhr.js</code><br>
在这条语句 <code>var request = new XMLHttpRequest();</code><br> <code>chrome</code> 浏览器中 打个断点调试下，再根据调用栈来细看具体函数等实现。<br></p> <p><code>Call Stack</code></p> <div class="language-bash extra-class"><pre class="language-bash"><code>dispatchXhrRequest <span class="token punctuation">(</span>xhr.js:19<span class="token punctuation">)</span>
xhrAdapter <span class="token punctuation">(</span>xhr.js:12<span class="token punctuation">)</span>
dispatchRequest <span class="token punctuation">(</span>dispatchRequest.js:60<span class="token punctuation">)</span>
Promise.then <span class="token punctuation">(</span>async<span class="token punctuation">)</span>
request <span class="token punctuation">(</span>Axios.js:54<span class="token punctuation">)</span>
wrap <span class="token punctuation">(</span>bind.js:10<span class="token punctuation">)</span>
submit.onclick <span class="token punctuation">((</span>index<span class="token punctuation">)</span>:138<span class="token punctuation">)</span>
</code></pre></div><p>简述下流程：<br></p> <ol><li><code>Send Request</code> 按钮点击 <code>submit.onclick</code><br></li> <li>调用 <code>axios</code> 函数实际上是调用 <code>Axios.prototype.request</code> 函数，而这个函数使用 <code>bind</code> 返回的一个名为<code>wrap</code>的函数。<br></li> <li>调用 <code>Axios.prototype.request</code><br></li> <li>（有请求拦截器的情况下执行请求拦截器），中间会执行 <code>dispatchRequest</code>方法<br></li> <li><code>dispatchRequest</code> 之后调用 <code>adapter (xhrAdapter)</code><br></li> <li>最后调用 <code>Promise</code> 中的函数<code>dispatchXhrRequest</code>，（有响应拦截器的情况下最后会再调用响应拦截器）<br></li></ol> <p>如果仔细看了文章开始的<code>axios 结构关系图</code>，其实对这个流程也有大概的了解。</p> <p>接下来看 <code>Axios.prototype.request</code> 具体实现。</p> <h3 id="_5-2-axios-prototype-request-请求核心方法"><a href="#_5-2-axios-prototype-request-请求核心方法" class="header-anchor">#</a> 5.2 Axios.prototype.request 请求核心方法</h3> <p>这个函数是核心函数。
主要做了这几件事：</p> <blockquote><p>1.判断第一个参数是字符串，则设置 url,也就是支持<code>axios('example/url', [, config])</code>，也支持<code>axios({})</code>。<br>
2.合并默认参数和用户传递的参数<br>
3.设置请求的方法，默认是是<code>get</code>方法<br>
4.将用户设置的请求和响应拦截器、发送请求的<code>dispatchRequest</code>组成<code>Promise</code>链，最后返回还是<code>Promise</code>实例。<br>
也就是保证了请求前拦截器先执行，然后发送请求，再响应拦截器执行这样的顺序。<br>
也就是为啥最后还是可以<code>then</code>，<code>catch</code>方法的缘故。<br></p></blockquote> <div class="language-js extra-class"><pre class="language-js"><code><span class="token class-name">Axios</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function-variable function">request</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token function">request</span><span class="token punctuation">(</span><span class="token parameter">config</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">/*eslint no-param-reassign:0*/</span>
  <span class="token comment">// Allow for axios('example/url'[, config]) a la fetch API</span>
  <span class="token comment">// 这一段代码 其实就是 使 axios('example/url', [, config])</span>
  <span class="token comment">// config 参数可以省略</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">typeof</span> config <span class="token operator">===</span> <span class="token string">'string'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    config <span class="token operator">=</span> arguments<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span> <span class="token operator">||</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
    config<span class="token punctuation">.</span>url <span class="token operator">=</span> arguments<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
    config <span class="token operator">=</span> config <span class="token operator">||</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token comment">// 合并默认参数和用户传递的参数</span>
  config <span class="token operator">=</span> <span class="token function">mergeConfig</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>defaults<span class="token punctuation">,</span> config<span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token comment">// Set config.method</span>
  <span class="token comment">// 设置 请求方法，默认 get 。</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>config<span class="token punctuation">.</span>method<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    config<span class="token punctuation">.</span>method <span class="token operator">=</span> config<span class="token punctuation">.</span>method<span class="token punctuation">.</span><span class="token function">toLowerCase</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>defaults<span class="token punctuation">.</span>method<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    config<span class="token punctuation">.</span>method <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>defaults<span class="token punctuation">.</span>method<span class="token punctuation">.</span><span class="token function">toLowerCase</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
    config<span class="token punctuation">.</span>method <span class="token operator">=</span> <span class="token string">'get'</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
  <span class="token comment">// Hook up interceptors middleware</span>
  <span class="token comment">// 组成`Promise`链 这段拆开到后文再讲述</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre></div><h4 id="_5-2-1-组成promise链-返回promise实例"><a href="#_5-2-1-组成promise链-返回promise实例" class="header-anchor">#</a> 5.2.1 组成<code>Promise</code>链，返回<code>Promise</code>实例</h4> <blockquote><p>这部分：用户设置的请求和响应拦截器、发送请求的<code>dispatchRequest</code>组成<code>Promise</code>链。也就是保证了请求前拦截器先执行，然后发送请求，再响应拦截器执行这样的顺序<br>
也就是保证了请求前拦截器先执行，然后发送请求，再响应拦截器执行这样的顺序<br>
也就是为啥最后还是可以<code>then</code>，<code>catch</code>方法的缘故。<br></p></blockquote> <p>如果读者对<code>Promise</code>不熟悉，建议读阮老师的书籍《ES6 标准入门》。
<a href="http://es6.ruanyifeng.com/#docs/promise#Promise-resolve" target="_blank" rel="noopener noreferrer">阮一峰老师 的 ES6 Promise-resolve<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> 和 <a href="http://liubin.org/promises-book/" target="_blank" rel="noopener noreferrer">JavaScript Promise迷你书（中文版）<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></p> <div class="language-js extra-class"><pre class="language-js"><code>  <span class="token comment">// 组成`Promise`链</span>
  <span class="token comment">// Hook up interceptors middleware</span>
  <span class="token comment">// 把 xhr 请求 的 dispatchRequest 和 undefined 放在一个数组里</span>
  <span class="token keyword">var</span> chain <span class="token operator">=</span> <span class="token punctuation">[</span>dispatchRequest<span class="token punctuation">,</span> <span class="token keyword">undefined</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
  <span class="token comment">// 创建 Promise 实例</span>
  <span class="token keyword">var</span> promise <span class="token operator">=</span> Promise<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span>config<span class="token punctuation">)</span><span class="token punctuation">;</span>

 <span class="token comment">// 遍历用户设置的请求拦截器 放到数组的 chain 前面</span>
  <span class="token keyword">this</span><span class="token punctuation">.</span>interceptors<span class="token punctuation">.</span>request<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token function">unshiftRequestInterceptors</span><span class="token punctuation">(</span><span class="token parameter">interceptor</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    chain<span class="token punctuation">.</span><span class="token function">unshift</span><span class="token punctuation">(</span>interceptor<span class="token punctuation">.</span>fulfilled<span class="token punctuation">,</span> interceptor<span class="token punctuation">.</span>rejected<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

 <span class="token comment">// 遍历用户设置的响应拦截器 放到数组的 chain 后面</span>
  <span class="token keyword">this</span><span class="token punctuation">.</span>interceptors<span class="token punctuation">.</span>response<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token function">pushResponseInterceptors</span><span class="token punctuation">(</span><span class="token parameter">interceptor</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    chain<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>interceptor<span class="token punctuation">.</span>fulfilled<span class="token punctuation">,</span> interceptor<span class="token punctuation">.</span>rejected<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

 <span class="token comment">// 遍历 chain 数组，直到遍历 chain.length 为 0</span>
  <span class="token keyword">while</span> <span class="token punctuation">(</span>chain<span class="token punctuation">.</span>length<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">// 两两对应移出来 放到 then 的两个参数里。</span>
    promise <span class="token operator">=</span> promise<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span>chain<span class="token punctuation">.</span><span class="token function">shift</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> chain<span class="token punctuation">.</span><span class="token function">shift</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token keyword">return</span> promise<span class="token punctuation">;</span>
</code></pre></div><div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">var</span> promise <span class="token operator">=</span> Promise<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span>config<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>解释下这句。作用是生成<code>Promise</code>实例。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">var</span> promise <span class="token operator">=</span> Promise<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span><span class="token punctuation">{</span>name<span class="token operator">:</span> <span class="token string">'若川'</span><span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token comment">// 等价于</span>
<span class="token comment">// new Promise(resolve =&gt; resolve({name: '若川'}))</span>
promise<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">config</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>config<span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// {name: &quot;若川&quot;}</span>
</code></pre></div><p>同样解释下后文会出现的<code>Promise.reject(error);</code>：</p> <div class="language-js extra-class"><pre class="language-js"><code>Promise<span class="token punctuation">.</span><span class="token function">reject</span><span class="token punctuation">(</span>error<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">var</span> promise <span class="token operator">=</span> Promise<span class="token punctuation">.</span><span class="token function">reject</span><span class="token punctuation">(</span><span class="token punctuation">{</span>name<span class="token operator">:</span> <span class="token string">'若川'</span><span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token comment">// 等价于</span>
<span class="token comment">// new Promise(reject =&gt; reject({name: '若川'}))</span>

<span class="token comment">// promise.then(null, function (config){</span>
<span class="token comment">//   console.log(config)</span>
<span class="token comment">// });</span>
<span class="token comment">// 等价于</span>
promise<span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">config</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>config<span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// {name: &quot;若川&quot;}</span>
</code></pre></div><p>接下来结合例子，来理解这段代码。<br>
很遗憾，在<code>example</code>文件夹没有拦截器的例子。笔者在<code>example</code>中在<code>example/get</code>的基础上添加了一个拦截器的示例。<code>axios/examples/interceptors</code>，便于读者调试。</p> <div class="language-bash extra-class"><pre class="language-bash"><code>node ./examples/server.js -p <span class="token number">5000</span>
</code></pre></div><p><code>promise = promise.then(chain.shift(), chain.shift());</code>这段代码打个断点。</p> <p>会得到这样的这张图。
<img src="/assets/img/request-promise-chain.ecb64ef1.png" alt="request方法中promise链"></p> <p>特别关注下，右侧，<code>local</code>中的<code>chain</code>数组。也就是这样的结构。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">var</span> chain <span class="token operator">=</span> <span class="token punctuation">[</span>
  <span class="token string">'请求成功拦截2'</span><span class="token punctuation">,</span> <span class="token string">'请求失败拦截2'</span><span class="token punctuation">,</span>  
  <span class="token string">'请求成功拦截1'</span><span class="token punctuation">,</span> <span class="token string">'请求失败拦截1'</span><span class="token punctuation">,</span>  
  dispatch<span class="token punctuation">,</span>  <span class="token keyword">undefined</span><span class="token punctuation">,</span>
  <span class="token string">'响应成功拦截1'</span><span class="token punctuation">,</span> <span class="token string">'响应失败拦截1'</span><span class="token punctuation">,</span>
  <span class="token string">'响应成功拦截2'</span><span class="token punctuation">,</span> <span class="token string">'响应失败拦截2'</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span>
</code></pre></div><p>这段代码相对比较绕。也就是会生成如下类似的代码，中间会调用<code>dispatchRequest</code>方法。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// config 是 用户配置和默认配置合并的</span>
<span class="token keyword">var</span> promise <span class="token operator">=</span> Promise<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span>config<span class="token punctuation">)</span><span class="token punctuation">;</span>
promise<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token string">'请求成功拦截2'</span><span class="token punctuation">,</span> <span class="token string">'请求失败拦截2'</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token string">'请求成功拦截1'</span><span class="token punctuation">,</span> <span class="token string">'请求失败拦截1'</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span>dispatchRequest<span class="token punctuation">,</span> <span class="token keyword">undefined</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token string">'响应成功拦截1'</span><span class="token punctuation">,</span> <span class="token string">'响应失败拦截1'</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token string">'响应成功拦截2'</span><span class="token punctuation">,</span> <span class="token string">'响应失败拦截2'</span><span class="token punctuation">)</span>

<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token string">'用户写的业务处理函数'</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token string">'用户写的报错业务处理函数'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>这里提下<code>promise</code> <code>then</code>和<code>catch</code>知识：<br> <code>Promise.prototype.then</code>方法的第一个参数是<code>resolved</code>状态的回调函数，第二个参数（可选）是<code>rejected</code>状态的回调函数。所以是成对出现的。<br> <code>Promise.prototype.catch</code>方法是<code>.then(null, rejection)</code>或<code>.then(undefined, rejection)</code>的别名，用于指定发生错误时的回调函数。<br> <code>then</code>方法返回的是一个新的<code>Promise</code>实例（注意，不是原来那个<code>Promise</code>实例）。因此可以采用链式写法，即<code>then</code>方法后面再调用另一个<code>then</code>方法。<br></p> <p>结合上述的例子更详细一点，代码则是这样的。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">var</span> promise <span class="token operator">=</span> Promise<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span>config<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// promise.then('请求成功拦截2', '请求失败拦截2')</span>
promise<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token function">requestSuccess2</span><span class="token punctuation">(</span><span class="token parameter">config</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'------request------success------2'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> config<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token function">requestError2</span><span class="token punctuation">(</span><span class="token parameter">error</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'------response------error------2'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> Promise<span class="token punctuation">.</span><span class="token function">reject</span><span class="token punctuation">(</span>error<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>

<span class="token comment">// .then('请求成功拦截1', '请求失败拦截1')</span>
<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token function">requestSuccess1</span><span class="token punctuation">(</span><span class="token parameter">config</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'------request------success------1'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> config<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token function">requestError1</span><span class="token punctuation">(</span><span class="token parameter">error</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'------response------error------1'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> Promise<span class="token punctuation">.</span><span class="token function">reject</span><span class="token punctuation">(</span>error<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>

<span class="token comment">// .then(dispatchRequest, undefined)</span>
<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span> <span class="token keyword">function</span> <span class="token function">dispatchRequest</span><span class="token punctuation">(</span><span class="token parameter">config</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">/**
    * 适配器返回的也是Promise 实例
      adapter = function xhrAdapter(config) {
            return new Promise(function dispatchXhrRequest(resolve, reject) {})
      }
    **/</span>
  <span class="token keyword">return</span> <span class="token function">adapter</span><span class="token punctuation">(</span>config<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token function">onAdapterResolution</span><span class="token punctuation">(</span><span class="token parameter">response</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">// 省略代码 ...</span>
    <span class="token keyword">return</span> response<span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token function">onAdapterRejection</span><span class="token punctuation">(</span><span class="token parameter">reason</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">// 省略代码 ...</span>
    <span class="token keyword">return</span> Promise<span class="token punctuation">.</span><span class="token function">reject</span><span class="token punctuation">(</span>reason<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token keyword">undefined</span><span class="token punctuation">)</span>

<span class="token comment">// .then('响应成功拦截1', '响应失败拦截1')</span>
<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token function">responseSuccess1</span><span class="token punctuation">(</span><span class="token parameter">response</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'------response------success------1'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> response<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token function">responseError1</span><span class="token punctuation">(</span><span class="token parameter">error</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'------response------error------1'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> Promise<span class="token punctuation">.</span><span class="token function">reject</span><span class="token punctuation">(</span>error<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>

<span class="token comment">// .then('响应成功拦截2', '响应失败拦截2')</span>
<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token function">responseSuccess2</span><span class="token punctuation">(</span><span class="token parameter">response</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'------response------success------2'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> response<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token function">responseError2</span><span class="token punctuation">(</span><span class="token parameter">error</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'------response------error------2'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> Promise<span class="token punctuation">.</span><span class="token function">reject</span><span class="token punctuation">(</span>error<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>

<span class="token comment">// .then('用户写的业务处理函数')</span>
<span class="token comment">// .catch('用户写的报错业务处理函数');</span>
<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">response</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'哈哈哈，终于获取到数据了'</span><span class="token punctuation">,</span> response<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">err</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'哎呀，怎么报错了'</span><span class="token punctuation">,</span> err<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>仔细看这段<code>Promise</code>链式调用，代码都类似。<code>then</code>方法最后返回的参数，就是下一个<code>then</code>方法第一个参数。<br> <code>catch</code>错误捕获，都返回<code>Promise.reject(error)</code>，这是为了便于用户<code>catch</code>时能捕获到错误。</p> <p>举个例子：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">var</span> p1 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
 <span class="token function">reject</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token punctuation">{</span>name<span class="token operator">:</span> <span class="token string">'若川'</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

p1<span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token parameter">err</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>res<span class="token punctuation">,</span> <span class="token string">'err'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> Promise<span class="token punctuation">.</span><span class="token function">reject</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token parameter">err</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
 console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>err<span class="token punctuation">,</span> <span class="token string">'err1'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token parameter">err</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
 console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>err<span class="token punctuation">,</span> <span class="token string">'err2'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p><code>err2</code>不会捕获到，也就是不会执行，但如果都返回了<code>return Promise.reject(err)</code>，则可以捕获到。</p> <p>最后画个图总结下 <code>Promise</code> 链式调用。</p> <p><img src="/assets/img/axios-promise-chain.e4fa2152.png" alt="axios promise 链式调用"></p> <blockquote><p>小结：1. 请求和响应的拦截器可以写<code>Promise</code>。<br>
2. 如果设置了多个请求响应器，后设置的先执行。<br>
3. 如果设置了多个响应拦截器，先设置的先执行。<br></p></blockquote> <p><code>dispatchRequest(config)</code> 这里的<code>config</code>是请求成功拦截器返回的。接下来看<code>dispatchRequest</code>函数。</p> <h3 id="_5-3-dispatchrequest-最终派发请求"><a href="#_5-3-dispatchrequest-最终派发请求" class="header-anchor">#</a> 5.3 dispatchRequest 最终派发请求</h3> <p>这个函数主要做了如下几件事情：<br></p> <blockquote><p>1.如果已经取消，则 <code>throw</code> 原因报错，使<code>Promise</code>走向<code>rejected</code>。<br>
2.确保 <code>config.header</code> 存在。<br>
3.利用用户设置的和默认的请求转换器转换数据。<br>
4.拍平 <code>config.header</code>。<br>
5.删除一些 <code>config.header</code>。<br>
6.返回适配器<code>adapter</code>（<code>Promise</code>实例）执行后 <code>then</code>执行后的 <code>Promise</code>实例。返回结果传递给响应拦截器处理。<br></p></blockquote> <div class="language-js extra-class"><pre class="language-js"><code><span class="token string">'use strict'</span><span class="token punctuation">;</span>
<span class="token comment">// utils 工具函数</span>
<span class="token keyword">var</span> utils <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'./../utils'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 转换数据</span>
<span class="token keyword">var</span> transformData <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'./transformData'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 取消状态</span>
<span class="token keyword">var</span> isCancel <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'../cancel/isCancel'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 默认参数</span>
<span class="token keyword">var</span> defaults <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'../defaults'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">/**
 * 抛出 错误原因，使`Promise`走向`rejected`
 */</span>
<span class="token keyword">function</span> <span class="token function">throwIfCancellationRequested</span><span class="token punctuation">(</span><span class="token parameter">config</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>config<span class="token punctuation">.</span>cancelToken<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    config<span class="token punctuation">.</span>cancelToken<span class="token punctuation">.</span><span class="token function">throwIfRequested</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token comment">/**
 * Dispatch a request to the server using the configured adapter.
 *
 * @param {object} config The config that is to be used for the request
 * @returns {Promise} The Promise to be fulfilled
 */</span>
module<span class="token punctuation">.</span><span class="token function-variable function">exports</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token function">dispatchRequest</span><span class="token punctuation">(</span><span class="token parameter">config</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// 取消相关</span>
  <span class="token function">throwIfCancellationRequested</span><span class="token punctuation">(</span>config<span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token comment">// Ensure headers exist</span>
  <span class="token comment">// 确保 headers 存在</span>
  config<span class="token punctuation">.</span>headers <span class="token operator">=</span> config<span class="token punctuation">.</span>headers <span class="token operator">||</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span>

  <span class="token comment">// Transform request data</span>
  <span class="token comment">// 转换请求的数据</span>
  config<span class="token punctuation">.</span>data <span class="token operator">=</span> <span class="token function">transformData</span><span class="token punctuation">(</span>
    config<span class="token punctuation">.</span>data<span class="token punctuation">,</span>
    config<span class="token punctuation">.</span>headers<span class="token punctuation">,</span>
    config<span class="token punctuation">.</span>transformRequest
  <span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token comment">// Flatten headers</span>
  <span class="token comment">// 拍平 headers</span>
  config<span class="token punctuation">.</span>headers <span class="token operator">=</span> utils<span class="token punctuation">.</span><span class="token function">merge</span><span class="token punctuation">(</span>
    config<span class="token punctuation">.</span>headers<span class="token punctuation">.</span>common <span class="token operator">||</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span>
    config<span class="token punctuation">.</span>headers<span class="token punctuation">[</span>config<span class="token punctuation">.</span>method<span class="token punctuation">]</span> <span class="token operator">||</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span>
    config<span class="token punctuation">.</span>headers <span class="token operator">||</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token comment">// 以下这些方法 删除 headers</span>
  utils<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span>
    <span class="token punctuation">[</span><span class="token string">'delete'</span><span class="token punctuation">,</span> <span class="token string">'get'</span><span class="token punctuation">,</span> <span class="token string">'head'</span><span class="token punctuation">,</span> <span class="token string">'post'</span><span class="token punctuation">,</span> <span class="token string">'put'</span><span class="token punctuation">,</span> <span class="token string">'patch'</span><span class="token punctuation">,</span> <span class="token string">'common'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token keyword">function</span> <span class="token function">cleanHeaderConfig</span><span class="token punctuation">(</span><span class="token parameter">method</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">delete</span> config<span class="token punctuation">.</span>headers<span class="token punctuation">[</span>method<span class="token punctuation">]</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token comment">// adapter 适配器部分 拆开 放在下文讲</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre></div><h4 id="_5-3-1-dispatchrequest-之-transformdata-转换数据"><a href="#_5-3-1-dispatchrequest-之-transformdata-转换数据" class="header-anchor">#</a> 5.3.1 dispatchRequest 之 transformData 转换数据</h4> <p>上文的代码里有个函数 <code>transformData</code> ，这里解释下。其实就是遍历传递的函数数组 对数据操作，最后返回数据。</p> <p><code>axios.defaults.transformResponse</code> 数组中默认就有一个函数，所以使用<code>concat</code>链接自定义的函数。</p> <p>使用：</p> <p>文件路径
<code>axios/examples/transform-response/index.html</code></p> <p>这段代码其实就是对时间格式的字符串转换成时间对象，可以直接调用<code>getMonth</code>等方法。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">var</span> <span class="token constant">ISO_8601</span> <span class="token operator">=</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">(\d{4}-\d{2}-\d{2})T(\d{2}:\d{2}:\d{2})Z</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">;</span>
<span class="token keyword">function</span> <span class="token function">formatDate</span><span class="token punctuation">(</span><span class="token parameter">d</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token punctuation">(</span>d<span class="token punctuation">.</span><span class="token function">getMonth</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">'/'</span> <span class="token operator">+</span> d<span class="token punctuation">.</span><span class="token function">getDate</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">'/'</span> <span class="token operator">+</span> d<span class="token punctuation">.</span><span class="token function">getFullYear</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

axios<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'https://api.github.com/users/mzabriskie'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
  transformResponse<span class="token operator">:</span> axios<span class="token punctuation">.</span>defaults<span class="token punctuation">.</span>transformResponse<span class="token punctuation">.</span><span class="token function">concat</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">data<span class="token punctuation">,</span> headers</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    Object<span class="token punctuation">.</span><span class="token function">keys</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">k</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token constant">ISO_8601</span><span class="token punctuation">.</span><span class="token function">test</span><span class="token punctuation">(</span>data<span class="token punctuation">[</span>k<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        data<span class="token punctuation">[</span>k<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span>Date<span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>data<span class="token punctuation">[</span>k<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> data<span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">res</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'created'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>innerHTML <span class="token operator">=</span> <span class="token function">formatDate</span><span class="token punctuation">(</span>res<span class="token punctuation">.</span>data<span class="token punctuation">.</span>created_at<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>源码：</p> <p>就是遍历数组，调用数组里的传递 <code>data</code> 和 <code>headers</code> 参数调用函数。</p> <div class="language-js extra-class"><pre class="language-js"><code>module<span class="token punctuation">.</span><span class="token function-variable function">exports</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token function">transformData</span><span class="token punctuation">(</span><span class="token parameter">data<span class="token punctuation">,</span> headers<span class="token punctuation">,</span> fns</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">/*eslint no-param-reassign:0*/</span>
  utils<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span>fns<span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token function">transform</span><span class="token punctuation">(</span><span class="token parameter">fn</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    data <span class="token operator">=</span> <span class="token function">fn</span><span class="token punctuation">(</span>data<span class="token punctuation">,</span> headers<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">return</span> data<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre></div><h4 id="_5-3-2-dispatchrequest-之-adapter-适配器执行部分"><a href="#_5-3-2-dispatchrequest-之-adapter-适配器执行部分" class="header-anchor">#</a> 5.3.2 dispatchRequest 之 adapter 适配器执行部分</h4> <p>适配器，在设计模式中称之为适配器模式。讲个生活中简单的例子，大家就容易理解。</p> <p>我们常用以前手机耳机孔都是圆孔，而现在基本是耳机孔和充电接口合二为一。统一为<code>typec</code>。</p> <p>这时我们需要需要一个<code>typec转圆孔的转接口</code>，这就是适配器。</p> <div class="language-js extra-class"><pre class="language-js"><code>  <span class="token comment">// adapter 适配器部分</span>
  <span class="token keyword">var</span> adapter <span class="token operator">=</span> config<span class="token punctuation">.</span>adapter <span class="token operator">||</span> defaults<span class="token punctuation">.</span>adapter<span class="token punctuation">;</span>

  <span class="token keyword">return</span> <span class="token function">adapter</span><span class="token punctuation">(</span>config<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token function">onAdapterResolution</span><span class="token punctuation">(</span><span class="token parameter">response</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token function">throwIfCancellationRequested</span><span class="token punctuation">(</span>config<span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token comment">// Transform response data</span>
    <span class="token comment">// 转换响应的数据</span>
    response<span class="token punctuation">.</span>data <span class="token operator">=</span> <span class="token function">transformData</span><span class="token punctuation">(</span>
      response<span class="token punctuation">.</span>data<span class="token punctuation">,</span>
      response<span class="token punctuation">.</span>headers<span class="token punctuation">,</span>
      config<span class="token punctuation">.</span>transformResponse
    <span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">return</span> response<span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token function">onAdapterRejection</span><span class="token punctuation">(</span><span class="token parameter">reason</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token function">isCancel</span><span class="token punctuation">(</span>reason<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token comment">// 取消相关</span>
      <span class="token function">throwIfCancellationRequested</span><span class="token punctuation">(</span>config<span class="token punctuation">)</span><span class="token punctuation">;</span>

      <span class="token comment">// Transform response data</span>
      <span class="token comment">// 转换响应的数据</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span>reason <span class="token operator">&amp;&amp;</span> reason<span class="token punctuation">.</span>response<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        reason<span class="token punctuation">.</span>response<span class="token punctuation">.</span>data <span class="token operator">=</span> <span class="token function">transformData</span><span class="token punctuation">(</span>
          reason<span class="token punctuation">.</span>response<span class="token punctuation">.</span>data<span class="token punctuation">,</span>
          reason<span class="token punctuation">.</span>response<span class="token punctuation">.</span>headers<span class="token punctuation">,</span>
          config<span class="token punctuation">.</span>transformResponse
        <span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">return</span> Promise<span class="token punctuation">.</span><span class="token function">reject</span><span class="token punctuation">(</span>reason<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>接下来看具体的 <code>adapter</code>。</p> <h3 id="_5-4-adapter-适配器-真正发送请求"><a href="#_5-4-adapter-适配器-真正发送请求" class="header-anchor">#</a> 5.4 adapter 适配器 真正发送请求</h3> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">var</span> adapter <span class="token operator">=</span> config<span class="token punctuation">.</span>adapter <span class="token operator">||</span> defaults<span class="token punctuation">.</span>adapter<span class="token punctuation">;</span>
</code></pre></div><p>看了上文的 <code>adapter</code>，可以知道支持用户自定义。比如可以通过微信小程序 <code>wx.request</code> 按照要求也写一个 <code>adapter</code>。<br>
接着来看下 <code>defaults.ddapter</code>。<br>
文件路径：<code>axios/lib/defaults.js</code></p> <p>根据当前环境引入，如果是浏览器环境引入<code>xhr</code>，是<code>node</code>环境则引入<code>http</code>。<br>
类似判断<code>node</code>环境，也在<a href="https://github.com/getsentry/sentry-javascript/blob/a876d46c61e2618e3c3a3e1710f77419331a9248/packages/utils/src/misc.ts#L37-L40" target="_blank" rel="noopener noreferrer"><code>sentry-javascript</code><span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>源码中有看到。<br></p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">getDefaultAdapter</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">var</span> adapter<span class="token punctuation">;</span>
  <span class="token comment">// 根据 XMLHttpRequest 判断</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">typeof</span> XMLHttpRequest <span class="token operator">!==</span> <span class="token string">'undefined'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">// For browsers use XHR adapter</span>
    adapter <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'./adapters/xhr'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">// 根据 process 判断</span>
  <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">typeof</span> process <span class="token operator">!==</span> <span class="token string">'undefined'</span> <span class="token operator">&amp;&amp;</span> <span class="token class-name">Object</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span>process<span class="token punctuation">)</span> <span class="token operator">===</span> <span class="token string">'[object process]'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">// For node use HTTP adapter</span>
    adapter <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'./adapters/http'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
  <span class="token keyword">return</span> adapter<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">var</span> defaults <span class="token operator">=</span> <span class="token punctuation">{</span>
  adapter<span class="token operator">:</span> <span class="token function">getDefaultAdapter</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token comment">// ...</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre></div><p><code>xhr</code></p> <p>接下来就是我们熟悉的 <code>XMLHttpRequest</code> 对象。</p> <p>可能读者不了解可以参考<a href="https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest" target="_blank" rel="noopener noreferrer">XMLHttpRequest MDN 文档<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>。</p> <p>主要提醒下：<code>onabort</code>是请求取消事件，<code>withCredentials</code>是一个布尔值，用来指定跨域 <code>Access-Control</code> 请求是否应带有授权信息，如 <code>cookie</code> 或授权 <code>header</code> 头。</p> <p>这块代码有删减，具体可以看<a href="https://github.com/lxchuan12/axios-analysis/blob/master/axios/lib/adapters/xhr.js" target="_blank" rel="noopener noreferrer">若川的<code>axios-analysis</code>仓库<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>，也可以克隆笔者的<code>axios-analysis</code>仓库调试时再具体分析。</p> <div class="language-js extra-class"><pre class="language-js"><code>module<span class="token punctuation">.</span><span class="token function-variable function">exports</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token function">xhrAdapter</span><span class="token punctuation">(</span><span class="token parameter">config</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token function">dispatchXhrRequest</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">// 这块代码有删减</span>
    <span class="token keyword">var</span> request <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">XMLHttpRequest</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    request<span class="token punctuation">.</span><span class="token function">open</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    request<span class="token punctuation">.</span>timeout <span class="token operator">=</span> config<span class="token punctuation">.</span>timeout<span class="token punctuation">;</span>
    <span class="token comment">// 监听 state 改变</span>
    request<span class="token punctuation">.</span><span class="token function-variable function">onreadystatechange</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token function">handleLoad</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>request <span class="token operator">||</span> request<span class="token punctuation">.</span>readyState <span class="token operator">!==</span> <span class="token number">4</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
      <span class="token comment">// ...</span>
    <span class="token punctuation">}</span>
    <span class="token comment">// 取消</span>
    request<span class="token punctuation">.</span><span class="token function-variable function">onabort</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
    <span class="token comment">// 错误</span>
    request<span class="token punctuation">.</span><span class="token function-variable function">onerror</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
    <span class="token comment">// 超时</span>
    request<span class="token punctuation">.</span><span class="token function-variable function">ontimeout</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
    <span class="token comment">// cookies 跨域携带 cookies 面试官常喜欢考这个</span>
    <span class="token comment">// 一个布尔值，用来指定跨域 Access-Control 请求是否应带有授权信息，如 cookie 或授权 header 头。</span>
    <span class="token comment">// Add withCredentials to request if needed</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>utils<span class="token punctuation">.</span><span class="token function">isUndefined</span><span class="token punctuation">(</span>config<span class="token punctuation">.</span>withCredentials<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      request<span class="token punctuation">.</span>withCredentials <span class="token operator">=</span> <span class="token operator">!</span><span class="token operator">!</span>config<span class="token punctuation">.</span>withCredentials<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">// 上传下载进度相关</span>
    <span class="token comment">// Handle progress if needed</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">typeof</span> config<span class="token punctuation">.</span>onDownloadProgress <span class="token operator">===</span> <span class="token string">'function'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      request<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'progress'</span><span class="token punctuation">,</span> config<span class="token punctuation">.</span>onDownloadProgress<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">// Not all browsers support upload events</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">typeof</span> config<span class="token punctuation">.</span>onUploadProgress <span class="token operator">===</span> <span class="token string">'function'</span> <span class="token operator">&amp;&amp;</span> request<span class="token punctuation">.</span>upload<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      request<span class="token punctuation">.</span>upload<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'progress'</span><span class="token punctuation">,</span> config<span class="token punctuation">.</span>onUploadProgress<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">// Send the request</span>
    <span class="token comment">// 发送请求</span>
    request<span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span>requestData<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p>而实际上现在 <a href="https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API/Using_Fetch" target="_blank" rel="noopener noreferrer"><code>fetch</code><span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> 支持的很好了，阿里开源的 <a href="https://github.com/umijs/umi-request/blob/master/README_zh-CN.md" target="_blank" rel="noopener noreferrer">umi-request<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> 请求库，就是用<code>fetch</code>封装的，而不是用<code>XMLHttpRequest</code>。
文章末尾，大概讲述下 <code>umi-request</code> 和 <code>axios</code> 的区别。</p> <p><code>http</code></p> <p><code>http</code>这里就不详细叙述了，感兴趣的读者可以自行查看，<a href="https://github.com/lxchuan12/axios-analysis/blob/master/axios/lib/adapters/http.js" target="_blank" rel="noopener noreferrer">若川的<code>axios-analysis</code>仓库<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>。</p> <div class="language-js extra-class"><pre class="language-js"><code>module<span class="token punctuation">.</span><span class="token function-variable function">exports</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token function">httpAdapter</span><span class="token punctuation">(</span><span class="token parameter">config</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token function">dispatchHttpRequest</span><span class="token punctuation">(</span><span class="token parameter">resolvePromise<span class="token punctuation">,</span> rejectPromise</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre></div><p>上文 <code>dispatchRequest</code> 有取消模块，我觉得是重点，所以放在最后来细讲：</p> <h3 id="_5-5-dispatchrequest-之-取消模块"><a href="#_5-5-dispatchrequest-之-取消模块" class="header-anchor">#</a> 5.5 dispatchRequest 之 取消模块</h3> <p>可以使用<code>cancel token</code>取消请求。</p> <p>axios cancel token API 是基于撤销的 <code>promise</code> 取消提议。</p> <p>The axios cancel token API is based on the withdrawn <a href="https://github.com/tc39/proposal-cancelable-promises" target="_blank" rel="noopener noreferrer">cancelable promises proposal.<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></p> <p><a href="https://github.com/axios/axios#cancellation" target="_blank" rel="noopener noreferrer">axios 文档 cancellation<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></p> <p>文档上详细描述了两种使用方式。</p> <p>很遗憾，在<code>example</code>文件夹也没有取消的例子。笔者在<code>example</code>中在<code>example/get</code>的基础上添加了一个取消的示例。<code>axios/examples/cancel</code>，便于读者调试。</p> <div class="language-bash extra-class"><pre class="language-bash"><code>node ./examples/server.js -p <span class="token number">5000</span>
</code></pre></div><p><code>request</code>中的拦截器和<code>dispatch</code>中的取消这两个模块相对复杂，可以多调试调试，吸收消化。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> CancelToken <span class="token operator">=</span> axios<span class="token punctuation">.</span>CancelToken<span class="token punctuation">;</span>
<span class="token keyword">const</span> source <span class="token operator">=</span> CancelToken<span class="token punctuation">.</span><span class="token function">source</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

axios<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'/get/server'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
  cancelToken<span class="token operator">:</span> source<span class="token punctuation">.</span>token
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">err</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>axios<span class="token punctuation">.</span><span class="token function">isCancel</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Request canceled'</span><span class="token punctuation">,</span> err<span class="token punctuation">.</span>message<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
    <span class="token comment">// handle error</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// cancel the request (the message parameter is optional)</span>
<span class="token comment">// 取消函数。</span>
source<span class="token punctuation">.</span><span class="token function">cancel</span><span class="token punctuation">(</span><span class="token string">'哎呀，我被若川取消了'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><h4 id="_5-5-1-取消请求模块代码示例"><a href="#_5-5-1-取消请求模块代码示例" class="header-anchor">#</a> 5.5.1 取消请求模块代码示例</h4> <p>结合源码取消流程大概是这样的。这段放在代码在<code>axios/examples/cancel-token/index.html</code>。</p> <p>参数的 <code>config.cancelToken</code> 是触发了<code>source.cancel('哎呀，我被若川取消了');</code>才生成的。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// source.cancel('哎呀，我被若川取消了');</span>
<span class="token comment">// 点击取消时才会 生成 cancelToken 实例对象。</span>
<span class="token comment">// 点击取消后，会生成原因，看懂了这段在看之后的源码，可能就好理解了。</span>
<span class="token keyword">var</span> config <span class="token operator">=</span> <span class="token punctuation">{</span>
  name<span class="token operator">:</span> <span class="token string">'若川'</span><span class="token punctuation">,</span>
  <span class="token comment">// 这里简化了</span>
  cancelToken<span class="token operator">:</span> <span class="token punctuation">{</span>
        promise<span class="token operator">:</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">resolve</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
            <span class="token function">resolve</span><span class="token punctuation">(</span><span class="token punctuation">{</span> message<span class="token operator">:</span> <span class="token string">'哎呀，我被若川取消了'</span><span class="token punctuation">}</span><span class="token punctuation">)</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
        reason<span class="token operator">:</span> <span class="token punctuation">{</span> message<span class="token operator">:</span> <span class="token string">'哎呀，我被若川取消了'</span> <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token comment">// 取消 抛出异常方法</span>
<span class="token keyword">function</span> <span class="token function">throwIfCancellationRequested</span><span class="token punctuation">(</span><span class="token parameter">config</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
  <span class="token comment">// 取消的情况下执行这句</span>
  <span class="token keyword">if</span><span class="token punctuation">(</span>config<span class="token punctuation">.</span>cancelToken<span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token comment">//   这里源代码 便于执行，我改成具体代码</span>
    <span class="token comment">// config.cancelToken.throwIfRequested();</span>
    <span class="token comment">// if (this.reason) {</span>
    <span class="token comment">//     throw this.reason;</span>
    <span class="token comment">//   }</span>
    <span class="token keyword">if</span><span class="token punctuation">(</span>config<span class="token punctuation">.</span>cancelToken<span class="token punctuation">.</span>reason<span class="token punctuation">)</span><span class="token punctuation">{</span>
        <span class="token keyword">throw</span> config<span class="token punctuation">.</span>cancelToken<span class="token punctuation">.</span>reason<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token keyword">function</span> <span class="token function">dispatchRequest</span><span class="token punctuation">(</span><span class="token parameter">config</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
  <span class="token comment">// 有可能是执行到这里就取消了，所以抛出错误会被err2 捕获到</span>
  <span class="token function">throwIfCancellationRequested</span><span class="token punctuation">(</span>config<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token comment">//  adapter xhr适配器</span>
  <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">resovle<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword">var</span> request <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">XMLHttpRequest</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'request'</span><span class="token punctuation">,</span> request<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>config<span class="token punctuation">.</span>cancelToken<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// Handle cancellation</span>
        config<span class="token punctuation">.</span>cancelToken<span class="token punctuation">.</span>promise<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token function">onCanceled</span><span class="token punctuation">(</span><span class="token parameter">cancel</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>request<span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token keyword">return</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>

            request<span class="token punctuation">.</span><span class="token function">abort</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token function">reject</span><span class="token punctuation">(</span>cancel<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token comment">// Clean up request</span>
            request <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span>
  <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token comment">// 有可能是执行到这里就才取消 取消的情况下执行这句</span>
    <span class="token function">throwIfCancellationRequested</span><span class="token punctuation">(</span>config<span class="token punctuation">)</span><span class="token punctuation">;</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'res'</span><span class="token punctuation">,</span> res<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> res<span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span>
  <span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">reason</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token comment">// 有可能是执行到这里就才取消 取消的情况下执行这句</span>
    <span class="token function">throwIfCancellationRequested</span><span class="token punctuation">(</span>config<span class="token punctuation">)</span><span class="token punctuation">;</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'reason'</span><span class="token punctuation">,</span> reason<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> Promise<span class="token punctuation">.</span><span class="token function">reject</span><span class="token punctuation">(</span>reason<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">var</span> promise <span class="token operator">=</span> Promise<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span>config<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// 没设置拦截器的情况下是这样的</span>
promise
<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span>dispatchRequest<span class="token punctuation">,</span> <span class="token keyword">undefined</span><span class="token punctuation">)</span>
<span class="token comment">// 用户定义的then 和 catch</span>
<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'res1'</span><span class="token punctuation">,</span> res<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> res<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">err</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'err2'</span><span class="token punctuation">,</span> err<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> Promise<span class="token punctuation">.</span><span class="token function">reject</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// err2 {message: &quot;哎呀，我被若川取消了&quot;}</span>
</code></pre></div><h4 id="_5-5-2-接下来看取消模块的源码"><a href="#_5-5-2-接下来看取消模块的源码" class="header-anchor">#</a> 5.5.2 接下来看取消模块的源码</h4> <p>看如何通过生成<code>config.cancelToken</code>。</p> <p>文件路径：</p> <p><code>axios/lib/cancel/CancelToken.js</code></p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> CancelToken <span class="token operator">=</span> axios<span class="token punctuation">.</span>CancelToken<span class="token punctuation">;</span>
<span class="token keyword">const</span> source <span class="token operator">=</span> CancelToken<span class="token punctuation">.</span><span class="token function">source</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
source<span class="token punctuation">.</span><span class="token function">cancel</span><span class="token punctuation">(</span><span class="token string">'哎呀，我被若川取消了'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>由示例看 <code>CancelToken.source</code>的实现，</p> <div class="language-js extra-class"><pre class="language-js"><code>CancelToken<span class="token punctuation">.</span><span class="token function-variable function">source</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token function">source</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">var</span> cancel<span class="token punctuation">;</span>
  <span class="token keyword">var</span> token <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">CancelToken</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token function">executor</span><span class="token punctuation">(</span><span class="token parameter">c</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    cancel <span class="token operator">=</span> c<span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token comment">// token</span>
  <span class="token keyword">return</span> <span class="token punctuation">{</span>
    token<span class="token operator">:</span> token<span class="token punctuation">,</span>
    cancel<span class="token operator">:</span> cancel
  <span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre></div><p>执行后<code>source</code>的大概结构是这样的。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token punctuation">{</span>
    token<span class="token operator">:</span> <span class="token punctuation">{</span>
    promise<span class="token operator">:</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">resolve</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
      <span class="token function">resolve</span><span class="token punctuation">(</span><span class="token punctuation">{</span> message<span class="token operator">:</span> <span class="token string">'哎呀，我被若川取消了'</span><span class="token punctuation">}</span><span class="token punctuation">)</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    reason<span class="token operator">:</span> <span class="token punctuation">{</span> message<span class="token operator">:</span> <span class="token string">'哎呀，我被若川取消了'</span> <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token function-variable function">cancel</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token function">cancel</span><span class="token punctuation">(</span><span class="token parameter">message</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>token<span class="token punctuation">.</span>reason<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token comment">// Cancellation has already been requested</span>
      <span class="token comment">// 已经取消</span>
      <span class="token keyword">return</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    token<span class="token punctuation">.</span>reason <span class="token operator">=</span> <span class="token punctuation">{</span>message<span class="token operator">:</span> <span class="token string">'哎呀，我被若川取消了'</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><p>接着看 <code>new CancelToken</code></p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// CancelToken</span>
<span class="token comment">// 通过 CancelToken 来取消请求操作</span>
<span class="token keyword">function</span> <span class="token function">CancelToken</span><span class="token punctuation">(</span><span class="token parameter">executor</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">typeof</span> executor <span class="token operator">!==</span> <span class="token string">'function'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">TypeError</span><span class="token punctuation">(</span><span class="token string">'executor must be a function.'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token keyword">var</span> resolvePromise<span class="token punctuation">;</span>
  <span class="token keyword">this</span><span class="token punctuation">.</span>promise <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token function">promiseExecutor</span><span class="token punctuation">(</span><span class="token parameter">resolve</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    resolvePromise <span class="token operator">=</span> resolve<span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">var</span> token <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">;</span>
  <span class="token function">executor</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token function">cancel</span><span class="token punctuation">(</span><span class="token parameter">message</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>token<span class="token punctuation">.</span>reason<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token comment">// Cancellation has already been requested</span>
      <span class="token comment">// 已经取消</span>
      <span class="token keyword">return</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    token<span class="token punctuation">.</span>reason <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Cancel</span><span class="token punctuation">(</span>message<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">resolvePromise</span><span class="token punctuation">(</span>token<span class="token punctuation">.</span>reason<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

module<span class="token punctuation">.</span>exports <span class="token operator">=</span> CancelToken<span class="token punctuation">;</span>
</code></pre></div><p>发送请求的适配器里是这样使用的。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// xhr</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>config<span class="token punctuation">.</span>cancelToken<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// Handle cancellation</span>
  config<span class="token punctuation">.</span>cancelToken<span class="token punctuation">.</span>promise<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token function">onCanceled</span><span class="token punctuation">(</span><span class="token parameter">cancel</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>request<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">return</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    request<span class="token punctuation">.</span><span class="token function">abort</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">reject</span><span class="token punctuation">(</span>cancel<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">// Clean up request</span>
    request <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p><code>dispatchRequest</code> 中的<code>throwIfCancellationRequested</code>具体实现：throw 抛出异常。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// 抛出异常函数</span>
<span class="token keyword">function</span> <span class="token function">throwIfCancellationRequested</span><span class="token punctuation">(</span><span class="token parameter">config</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>config<span class="token punctuation">.</span>cancelToken<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    config<span class="token punctuation">.</span>cancelToken<span class="token punctuation">.</span><span class="token function">throwIfRequested</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token comment">// 抛出异常 用户 { message: '哎呀，我被若川取消了' }</span>
<span class="token class-name">CancelToken</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function-variable function">throwIfRequested</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token function">throwIfRequested</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>reason<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">throw</span> <span class="token keyword">this</span><span class="token punctuation">.</span>reason<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre></div><p>取消流程调用栈</p> <blockquote><p>1.source.cancel()<br>
2.resolvePromise(token.reason);<br>
3.config.cancelToken.promise.then(function onCanceled(cancel) {})<br></p></blockquote> <p>最后进入<code>request.abort();``reject(cancel);</code></p> <p>到这里取消的流程就介绍完毕了。主要就是通过传递配置参数<code>cancelToken</code>，取消时才会生成<code>cancelToken</code>，判断有，则抛出错误，使<code>Promise</code> 走向<code>rejected</code>，让用户捕获到消息{message: '用户设置的取消信息'}。</p> <p>文章写到这里就基本到接近尾声了。</p> <p>能读到最后，说明你已经超过很多人啦^_^</p> <p><code>axios</code>是非常优秀的请求库，但肯定也不能满足所有开发者的需求，接下来对比下其他库，看看其他开发者有什么具体需求。</p> <h2 id="_6-对比其他请求库"><a href="#_6-对比其他请求库" class="header-anchor">#</a> 6. 对比其他请求库</h2> <h3 id="_6-1-koajax"><a href="#_6-1-koajax" class="header-anchor">#</a> 6.1 KoAjax</h3> <p>FCC成都社区负责人水歌开源的<a href="https://github.com/EasyWebApp/KoAJAX" target="_blank" rel="noopener noreferrer">KoAJAX<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>。</p> <p><a href="https://mp.weixin.qq.com/s/hxCwiokl4uPXJscTQi42-A" target="_blank" rel="noopener noreferrer">如何用开源软件办一场技术大会？<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>
以下这篇文章中摘抄的一段。</p> <blockquote><p>前端请求库 —— KoAJAX
国内前端同学最常用的 HTTP 请求库应该是 axios 了吧？虽然它的 Interceptor（拦截器）API 是 .use()，但和 Node.js 的 Express、Koa 等框架的中间件模式完全不同，相比 jQuery .ajaxPrefilter()、dataFilter() 并没什么实质改进；上传、下载进度比 jQuery.Deferred() 还简陋，只是两个专门的回调选项。所以，它还是要对特定的需求记忆特定的 API，不够简洁。</p></blockquote> <blockquote><p>幸运的是，水歌在研究如何<a href="https://tech-query.me/onion-stack/" target="_blank" rel="noopener noreferrer">用 ES 2018 异步迭代器实现一个类 Koa 中间件引擎<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>的过程中，做出了一个更有实际价值的上层应用 —— KoAJAX。它的整个执行过程基于 Koa 式的中间件，而且它自己就是一个中间件调用栈。除了 RESTful API 常用的 .get()、.post()、.put()、.delete() 等快捷方法外，开发者就只需记住 .use() 和 next()，其它都是 ES 标准语法和 TS 类型推导。</p></blockquote> <h3 id="_6-2-umi-request-阿里开源的请求库"><a href="#_6-2-umi-request-阿里开源的请求库" class="header-anchor">#</a> 6.2 umi-request 阿里开源的请求库</h3> <p><a href="https://github.com/umijs/umi-request/blob/master/README_zh-CN.md" target="_blank" rel="noopener noreferrer">umi-request github 仓库<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></p> <p><code>umi-request</code> 与 <code>fetch</code>, <code>axios</code> 异同。</p> <p><img src="/assets/img/umi-request-image.6331073d.png" alt=" 与 ,  异同"></p> <p>不得不说，<code>umi-request</code> 确实强大，有兴趣的读者可以阅读下其源码。</p> <p>看懂<code>axios</code>的基础上，看懂<code>umi-request</code>源码应该不难。</p> <p>比如 <code>umi-request</code> 取消模块代码几乎与<code>axios</code>一模一样。</p> <h2 id="_7-总结"><a href="#_7-总结" class="header-anchor">#</a> 7. 总结</h2> <p>文章详细介绍了 <code>axios</code> 调试方法。详细介绍了 <code>axios</code> 构造函数，拦截器，取消等功能的实现。最后还对比了其他请求库。</p> <p>最后画个图总结一下axios的总体大致流程。</p> <p><img src="/assets/img/axios-all.41d4c89c.png" alt="axios的总体大致流程"></p> <p>解答下文章开头提的问题：</p> <p>如果你是求职者，项目写了运用了<code>axios</code>，面试官可能会问你：</p> <blockquote><p>1.为什么 <code>axios</code> 既可以当函数调用，也可以当对象使用，比如<code>axios({})</code>、<code>axios.get</code>。<br>
答：<code>axios</code>本质是函数，赋值了一些别名方法，比如<code>get</code>、<code>post</code>方法，可被调用，最终调用的还是<code>Axios.prototype.request</code>函数。<br>
2.简述 <code>axios</code> 调用流程。<br>
答：实际是调用的<code>Axios.prototype.request</code>方法，最终返回的是<code>promise</code>链式调用，实际请求是在<code>dispatchRequest</code>中派发的。<br>
3.有用过拦截器吗？原理是怎样的？<br>
答：用过，用<code>axios.interceptors.request.use</code>添加请求成功和失败拦截器函数，用<code>axios.interceptors.response.use</code>添加响应成功和失败拦截器函数。在<code>Axios.prototype.request</code>函数组成<code>promise</code>链式调用时，<code>Interceptors.protype.forEach</code>遍历请求和响应拦截器添加到真正发送请求<code>dispatchRequest</code>的两端，从而做到请求前拦截和响应后拦截。拦截器也支持用<code>Interceptors.protype.eject</code>方法移除。<br>
4.有使用<code>axios</code>的取消功能吗？是怎么实现的？<br>
答：用过，通过传递<code>config</code>配置<code>cancelToken</code>的形式，来取消的。判断有传<code>cancelToken</code>，在<code>promise</code>链式调用的<code>dispatchRequest</code>抛出错误，在<code>adapter</code>中<code>request.abort()</code>取消请求，使<code>promise</code>走向<code>rejected</code>，被用户捕获取消信息。<br>
5.为什么支持浏览器中发送请求也支持<code>node</code>发送请求？<br>
答：<code>axios.defaults.adapter</code>默认配置中根据环境判断是浏览器还是<code>node</code>环境，使用对应的适配器。适配器支持自定义。<br></p></blockquote> <p>回答面试官的问题，读者也可以根据自己的理解，组织语言，笔者的回答只是做一个参考。</p> <p><code>axios</code> 源码相对不多，打包后一千多行，比较容易看完，非常值得学习。</p> <p>建议 <code>clone</code> <a href="https://github.com/lxchuan12/axios-analysis" target="_blank" rel="noopener noreferrer">若川的 axios-analysis github 仓库<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>，按照文中方法自己调试，印象更深刻。<br></p> <p>基于<code>Promise</code>，构成<code>Promise</code>链，巧妙的设置请求拦截，发送请求，再试试响应拦截器。</p> <p><code>request</code>中的拦截器和<code>dispatch</code>中的取消这两个模块相对复杂，可以多调试调试，吸收消化。</p> <p><code>axios</code> 既是函数，是函数时调用的是<code>Axios.prototype.request</code>函数，又是对象，其上面有<code>get</code>、<code>post</code>等请求方法，最终也是调用<code>Axios.prototype.request</code>函数。</p> <p><code>axios</code> 源码中使用了挺多设计模式。比如工厂模式、迭代器模式、适配器模式等。如果想系统学习设计模式，一般比较推荐豆瓣评分9.1的<a href="https://book.douban.com/subject/26382780/" target="_blank" rel="noopener noreferrer">JavaScript设计模式与开发实践<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></p> <p>如果读者发现有不妥或可改善之处，再或者哪里没写明白的地方，欢迎评论指出。另外觉得写得不错，对您有些许帮助，可以点赞、评论、转发分享，也是对笔者的一种支持，非常感谢呀。</p> <h2 id="推荐阅读"><a href="#推荐阅读" class="header-anchor">#</a> 推荐阅读</h2> <p><a href="https://github.com/axios/axios" target="_blank" rel="noopener noreferrer">官方axios github 仓库<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a><br></p> <p>写文章前，搜索了以下几篇文章泛读了一下。有兴趣再对比看看以下这几篇，有代码调试的基础上，看起来也快。</p> <p>一直觉得多搜索几篇文章看，对自己学习知识更有用。有个词语叫主题阅读。大概意思就是一个主题一系列阅读。</p> <p><a href="https://juejin.im/post/5cb5d9bde51d456e62545abc" target="_blank" rel="noopener noreferrer">@叫我小明呀：Axios 源码解析<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a><br> <a href="https://zhuanlan.zhihu.com/p/37962469" target="_blank" rel="noopener noreferrer">@尼库尼库桑：深入浅出 axios 源码<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a><br> <a href="https://juejin.im/post/5b0ba2d56fb9a00a1357a334" target="_blank" rel="noopener noreferrer">@小贼先生_ronffy：Axios源码深度剖析 - AJAX新王者<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a><br> <a href="https://juejin.im/post/5d501512518825159e3d7be6" target="_blank" rel="noopener noreferrer">逐行解析Axios源码<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a><br> <a href="https://juejin.im/post/5d906269f265da5ba7451b02" target="_blank" rel="noopener noreferrer">[译]axios 是如何封装 HTTP 请求的<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a><br> <a href="https://zhuanlan.zhihu.com/p/50859466" target="_blank" rel="noopener noreferrer">知乎@Lee : TypeScript 重构 Axios 经验分享<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a><br></p> <h2 id="笔者另一个系列"><a href="#笔者另一个系列" class="header-anchor">#</a> 笔者另一个系列</h2> <p><a href="https://juejin.im/post/5c433e216fb9a049c15f841b" target="_blank" rel="noopener noreferrer">面试官问：JS的继承<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a><br> <a href="https://juejin.im/post/5c0c87b35188252e8966c78a" target="_blank" rel="noopener noreferrer">面试官问：JS的this指向<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a><br> <a href="https://juejin.im/post/5bf6c79bf265da6142738b29" target="_blank" rel="noopener noreferrer">面试官问：能否模拟实现JS的call和apply方法<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a><br> <a href="https://juejin.im/post/5bec4183f265da616b1044d7" target="_blank" rel="noopener noreferrer">面试官问：能否模拟实现JS的bind方法<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a><br> <a href="https://juejin.im/post/5bde7c926fb9a049f66b8b52" target="_blank" rel="noopener noreferrer">面试官问：能否模拟实现JS的new操作符<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a><br></p> <h2 id="关于"><a href="#关于" class="header-anchor">#</a> 关于</h2> <p>作者：常以<strong>若川</strong>为名混迹于江湖。前端路上 | PPT爱好者 | 所知甚少，唯善学。<br> <a href="https://lxchuan12.gitee.io" target="_blank" rel="noopener noreferrer">若川的博客<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>，使用<code>vuepress</code>重构了，阅读体验可能更好些<br> <a href="https://juejin.cn/user/1415826704971918/posts" target="_blank" rel="noopener noreferrer">掘金专栏<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>，欢迎关注~<br> <a href="https://segmentfault.com/blog/lxchuan12" target="_blank" rel="noopener noreferrer"><code>segmentfault</code>前端视野专栏<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>，欢迎关注~<br> <a href="https://zhuanlan.zhihu.com/lxchuan12" target="_blank" rel="noopener noreferrer">知乎前端视野专栏<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>，欢迎关注~<br> <a href="https://www.yuque.com/lxchuan12/blog" target="_blank" rel="noopener noreferrer">语雀前端视野专栏<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>，新增语雀专栏，欢迎关注~<br> <a href="https://github.com/lxchuan12/blog" target="_blank" rel="noopener noreferrer">github blog<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>，相关源码和资源都放在这里，求个<code>star</code>^_^~</p> <h2 id="欢迎加微信交流-微信公众号"><a href="#欢迎加微信交流-微信公众号" class="header-anchor">#</a> 欢迎加微信交流 微信公众号</h2> <p>可能比较有趣的微信公众号，长按扫码关注（<strong>回复pdf获取前端优质书籍pdf</strong>）。欢迎加笔者微信<code>ruochuan12</code>（注明来源，基本来者不拒），拉您进【前端视野交流群】，长期交流学习~</p> <p><img src="https://github.com/lxchuan12/blog/raw/master/docs/about/wechat-official-accounts-mini.jpg" alt="若川视野"></p></div> <footer class="page-edit"><!----> <div class="last-updated"><span class="prefix">最后更新时间:</span> <span class="time">4/3/2021, 4:37:20 PM</span></div></footer> <div class="page-nav"><p class="inner"><span class="prev">
      ←
      <a href="/koa/" class="prev">
        学习 koa 源码的整体架构，浅析koa洋葱模型原理和co原理
      </a></span> <span class="next"><a href="/vuex/">
        学习 vuex 源码整体架构，打造属于自己的状态管理库
      </a>
      →
    </span></p></div> </main></div><div class="global-ui"><BackToTop></BackToTop><!----></div></div>
    <script src="/assets/js/app.9fbcafa6.js" defer></script><script src="/assets/js/2.33539d56.js" defer></script><script src="/assets/js/14.c9f20b6b.js" defer></script><script src="/assets/js/23.72249401.js" defer></script>
  </body>
</html>
